Opaque Struct Tanımlama
Coddy'nin C Journey'sinin Object Oriented Programming bölümünün bir parçası — ders 18 / 61.
Artık opak işaretçi (opaque pointer) kavramını anladığınıza göre, kalıbın nasıl tamamlanacağını görelim. Başlık dosyası bir türün var olduğunu bildirir, ancak kaynak dosya, içinde gerçekte ne olduğunu tanımladığınız yerdir.
İşte kurulumun tamamı. İlk olarak, sadece ileriye dönük bildirimi (forward declaration) içeren başlık dosyası:
// counter.h
#ifndef COUNTER_H
#define COUNTER_H
typedef struct Counter Counter; // Tamamlanmamış tür
Counter *create_counter(int start);
void free_counter(Counter *c);
#endif
Ardından, kaynak dosyası gerçek struct tanımını içerir:
// counter.c
#include "counter.h"
#include <stdlib.h>
struct Counter {
int value; // Dışarıdan gizli!
int step;
};
Counter *create_counter(int start) {
Counter *c = malloc(sizeof(Counter));
c->value = start;
c->step = 1;
return c;
}
void free_counter(Counter *c) {
free(c);
}
Kilit nokta: struct Counter { ... } yalnızca .c dosyasında görünür. counter.h dosyasını dahil eden herhangi bir dosya Counter'ın var olduğunu bilir ancak value veya step üyelerini göremez. main.c içinde c->value yazmaya çalışmak bir derleyici hatasına neden olur—üyeler gerçekten görünmezdir.
Bu ayrım, C'deki kapsüllemenin (encapsulation) temelidir. Bir sonraki adım, getter ve setter fonksiyonları aracılığıyla kontrollü erişim sağlamaktır.
Görev
KolayOpaque pointer (mat işaretçi) desenini gösteren bir Timer modülü oluşturalım. Yapı (struct) tanımını kaynak dosyasının içinde gizleyerek, dahili üyelerini modülünüzü kullanan herhangi bir kod için tamamen görünmez hale getirme pratiği yapacaksınız.
Üç dosya oluşturacaksınız:
timer.h: Bu sizin genel arayüzünüzdür. Sadece bir ön bildirim (forward declaration) kullanarak opak birTimertürü bildirin—burada struct gövdesi olmamalı! Ayrıca iki fonksiyon bildirin:create_timer(saniye için bir tamsayı alır ve bir Timer işaretçisi döndürür) vefree_timer(bir Timer işaretçisi alır ve temizlik yapar).TIMER_Hsembolü ile include guard kullanın.timer.c: Sırrın saklandığı yer burasıdır. İki gizli üyeye sahip gerçekstruct Timeryapısını tanımlayın:int secondsveint running(çalışıyor için 1, durduruldu için 0 kullanın). Yapıyı tahsis etmek,secondsdeğerini sağlanan değerle başlatmak verunningdeğerini 1 olarak ayarlamak için kurucu (constructor) fonksiyonunuzu uygulayın. Belleği serbest bırakmak için yıkıcı (destructor) fonksiyonu uygulayın.main.c: Bir zamanlayıcı oluşturmak ve başarıyla oluşturulduğunu onaylamak için Timer modülünüzü kullanın. Yapı üyeleri gizli olduğu için onlara doğrudan erişemezsiniz—tüm mesele de bu! Sadece oluşturmayı onaylayan bir mesaj yazdırın, ardından zamanlayıcıyı serbest bırakın ve bir temizleme mesajı yazdırın.
Bir girdi alacaksınız: zamanlayıcıyı başlatmak için saniye sayısı (bir tamsayı).
Ana dosyanızda, sağlanan saniye değeriyle bir zamanlayıcı oluşturun. Bir oluşturma mesajı yazdırın, ardından zamanlayıcıyı serbest bırakın ve bir onay yazdırın.
Çıktıyı şu formatta yazdırın:
Timer created
Timer freedBuradaki temel nokta, main.c dosyasının Timer işaretçileriyle çalışabilmesi ancak seconds veya running üyelerine doğrudan erişme yolunun olmamasıdır. main.c içinde t->seconds yazmaya çalışmak bir derleyici hatasına neden olur çünkü struct gövdesi yalnızca timer.c içinde tanımlanmıştır. Bu gerçek bir kapsülleme (encapsulation) örneğidir—uygulama detayları modülünüzün kullanıcılarından tamamen gizlenir.
Kopya kağıdı
Opaque pointer deseni, bir türün bildirimini tanımından ayırarak uygulama detaylarını gizler.
Başlık dosyası yalnızca bir ön bildirim (forward declaration) içerir:
// counter.h
#ifndef COUNTER_H
#define COUNTER_H
typedef struct Counter Counter; // Tamamlanmamış tür
Counter *create_counter(int start);
void free_counter(Counter *c);
#endif
Kaynak dosya gerçek struct tanımını içerir:
// counter.c
#include "counter.h"
#include <stdlib.h>
struct Counter {
int value; // Dışarıdan gizli
int step;
};
Counter *create_counter(int start) {
Counter *c = malloc(sizeof(Counter));
c->value = start;
c->step = 1;
return c;
}
void free_counter(Counter *c) {
free(c);
}
Struct tanımı yalnızca .c dosyasında görünür. Başlık dosyasını dahil eden dosyalar türün var olduğunu bilir ancak üyelerine doğrudan erişemez. Bu, C'de gerçek kapsülleme (encapsulation) sağlar.
Kendin dene
#include <stdio.h>
#include "timer.h"
int main() {
int seconds;
scanf("%d", &seconds);
// TODO: Sağlanan saniye değeri ile bir zamanlayıcı oluştur
// TODO: "Timer created" yazdır
// TODO: Zamanlayıcıyı serbest bırak
// TODO: "Timer freed" yazdır
return 0;
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Object Oriented Programming bölümündeki tüm dersler
1Modüler Programlama Temelleri
Başlık DosyalarıInclude Guard'larKaynak DosyalarıStatik FonksiyonlarÖzet: Modüler Hesap Makinesi4Kapsülleme
Opaque Pointer KavramıOpaque Struct TanımlamaGetter ve Setter MetotlarıSetter Metotlarında DoğrulamaÖzet: Gizli Kutu2Nesneler ve Metotlar
Nesne Olarak Struct'lar'Self' İşaretçisiConst Doğruluğuİşaretçi vs DeğerYardımcı MetotlarÖzet: Point Manager5Proje: Basit Banka Hesabı
Proje KurulumuHesabın Oluşturulması3Nesne Yaşam Döngüsü
Constructor DeseniDestructor DeseniStack İlklendirmeDerin KopyalamaÖzet: String Wrapper6Kompozisyon Yoluyla Kalıtım
Struct Gömmeİlk Üye KuralıÜst Üyelere ErişimUpcastingÖzet: Şekil Hiyerarşisi