Bu sayfadaki yazılar
Sayfanın metni
Sayfa 79
Tabii ki pointer ile.
Bunları private alanda birer pointer ile tutsam, constructor'da oluşturup destructor'da silsem sorunum kalmayacak.
class Timer { public:
Timer() ;
~Timer() ;
Timer(Timer const &timer) ;
Timer &operator =(Timer const &timer) ;
void Start() ;
void Stop() ;
double GetTime() const ;
private:
bool counting_ ;
union LARGE_INTEGER ;
LARGE_INTEGER *frequency_ ;
LARGE_INTEGER *zero_ ;
(Not: Dinamik bellek kullanımına geçtiğimiz için varsayılan kopyalama işlemleri (element element kopyalama) isteğimizi karşılamayacak. Bu yüzden kendi kopyalama rutinlerimizi yazmamız gerekti.)
Timer sınıfını görüp Timer objeleri oluşturmak isteyen bir kaynak dosyasının artık windows.h’ı eklemesine gerek kalmadı. Çünkü gizli alandaki LARGE_INTEGER’ları kullanmayacak ve boylarını bilmesine gerek yok. Ve çünkü bütün pointerlar aynı boydadır! Tek yapmamız gereken bunun ne tür bir değişken olduğunu ön bildirim olarak derleyiciye vermek (struct).
Aslında daha rahat bir kullanım tüm private kısmı özel bir sınıf içine alıp tek bir pointer kullanmak.
class Timer { public:
Klavyeyle gezinmek için ← ve → tuşları.
Sayfa 78
Timer() ;
~Timer() ;
void Start() ;
void Stop() ;
double GetTime() const ;
private:
bool counting_ ;
LARGE_INTEGER frequency_ ;
LARGE_INTEGER zero_ ;
Timerımız için Windows’un yüksek hassaslıklı zamanlayıcılarını kullanacağız. Bunun için işlemciye özgü bir saatin frekansını (frequency_) ve başla dediğimiz anın zamanını (zero_) tutmamız gerekiyor. GetTime dediğimizde de kronometre çalışıyorsa (counting_) timerımız o anki süreye bakıp, başlangıç süresini çıkarıp, frekansı da kullanarak saniye cinsinden kronometre değerini dönüyor. Kronometre durmuşsa da en son durulan uzaklığı zero_‘ya atmış olmamıza güvenip bu değeri veriyor.
(Not: Burada basit bir yapı olacak, kronometre her zaman sıfırdan başlayacak. Olayı kavradıktan sonra pause ve hız ayarı gibi özellikler ekleyebilirsiniz.)
Tabii bu timer'ı kullanmak isteyenlerin LARGE_INTEGER'ın ne olduğunu bilmeleri, bu yüzden windows.h'ı kullanmaları gerekiyor. Bir diğer seçenek de Timer.h'ın tepesinde bu işi kendimiz yaparak sınıf kullanıcılarını bu dertten kurtarmamız. Her iki durumda da istenmeyen header'lardan kurtulamıyoruz.
Çözüm yöntemlerimiz neler olabilir?
LARGE_INTEGER'ın 64 bitlik tamsayı olduğunu varsayıp yerine favori 64 bitlik tipimizi koymak ve gereken her yerde tip geçişi yapmak? Sakın! Asla diğer tiplerin yapıları hakkında varsayımlarda bulunmayın. LARGE_INTEGER'ın ya da onu oluşturan parçaların en ufak değişikliğinde kendinizi milyonlarca satır düzeltmeye çalışırken buluyor olabilirsiniz.
Hassas saatler yerine standart kütüphanenin clock'unu kullanmak? Belki. Hassaslıkta epey bir kaybınız olacak ama en azından daha kolay port edilebilir bir kod elde edeceksiniz. Eksi olarak ise, kullanıcı istemeden ctime'ı eklemiş olacaksınız ve bu mantıkla devam ederseniz platforma özgü çok iyi özelliklerden mahrum kalacaksınız.
Benim istediğim ise hiçbir header eklemeye gerek bırakmayan, üzerinde çalıştığı platformun en iyi çözümünü kullanan ve bunu yaparken kullanıcıya herhangi bir şey yansıtmayan bir yöntem.
Opak Pointer Yöntemi
Sorunumuz LARGE_INTEGER'ı kullanabilmek için tanımına ihtiyacımız olması idi. Bu yöntem soruna çok basit yaklaşım sergiliyor. Tanıma ihtiyacımız var çünkü Timer objeleri oluşturabilmek için Timer objelerinin boyunu bilmeliyiz. Timer objelerinin boyunu hesaplamak için de LARGE_INTEGER'ların boyunu bilmeliyiz. Ama anahtar şu ki, kullanıcı asla zero_ ya da frequency_'yi kullanmayacak. Dolayısıyla onun bunların boyunu başka bir amaçla bilmesine gerek yok. Timer bu elemanların boyunu kullanıcıya göstermeden onları nasıl kullanabilir?