Yapılar, Sınıflar ve Arayüzler
Yapılar
Yapılar her tipten elemanlar içerebilen kümelerdir (void tipi dışında). Yapıların kullanımı mantıksal olarak ilişkili farklı tip verilerin bir araya getirilmesini sağlar.
Yapı Bildirimi
Yapı veri tipi şu tarif ile belirtilir:
struct yapı_ismi
{
elemanların_açıklaması
};
|
Yapı ismi bir tanımlayıcı (bir değişken veya fonksiyon ismi) şeklinde kullanılamaz. MQL5 yapı elemanlarının sıralama olmaksızın doğrudan birbirlerini takip ettiği not edilmelidir. Bu gibi bir sıralama C++ dilinde şu yönerge ile derleyiciye yaptırılır:
Eğer yapı içinde başka bir sıralama yapmak isterseniz doğru ölçüde yardımcı üyeler ve "dolgular" kullanın.
Örnek:
struct trade_settings
{
uchar slippage; // izin verilebilir slipaj (sapma) değeri 1 bayt
char reserved1; // 1 bayt atla
short reserved2; // 2 bayt atla
int reserved4; // başka bir 4 bayt atlandı. 8 baytlık sınır hizasını temin eder
double take; // kar sabitleme fiyatının değerleri
double stop; // koruyucu durdurma seviyesinin fiyat değeri
};
|
Sıralanmış yapıların bu tanımı, sadece içe aktarılmış dll fonksiyonlarına yapılacak veri aktarımları için gereklidir.
Uyarı: Bu örnek yanlış tasarlanmış veriler sergiler. Önce double tipli take ve stop gibi büyük değişkenlerin, ardından uchar tipli slippage üyesinin bildirilmesi daha iyi olacaktır. Bu durumda, verinin içsel temsili #pragma pack() içinde belirlenen değerden bağımsız olarak her zaman aynı olacaktır.
Eğer bir yapı string tipi ve veya dinamik dizi nesnesi şeklinde değişkenler içeriyorsa, derleyici yapı için gizli bir yapıcı fonksiyon atar. Bu yapıcı tüm string tipli üyeleri sıfırlar ve dinamik dizi nesnelerini düzgün şekilde başlatır.
Basit Yapılar
Dizgileri, nesne işaretçilerini, sınıf nesnelerini ve dinamik dizileri içermeyen yapılar basit yapılardır. Yapı değişkenleri ve bunların dizileri DLL dosyalarından aktarılan fonksiyonlara geçirilebilir.
Basit yapıların kopyalanmasına sadece iki durumda izin verilir:
- Nesne aynı yapı tipinden ise
- Nesnelerin köken bağı varsa, yani bir yapı diğerinden türetilmişse.
Örnek olarak, gömülü MqlTick yapısını kullanarak, aynı içeriğe sahip olan özel CustomMqlTick yapısını oluşturalım. Bu durumda derleyici MqlTick nesne değerinin CustomMqlTick tipli nesneye kopyalanmasına izin vermeyecektir. Uygun tipe yapılan doğrudan tip dönüşümü bile derleyici hatası verecektir:
//--- basit yapılar farklı tiplere dönüştürülemez
my_tick1=last_tick; // burada derleyici hata dönüşü yapar
//--- farklı tipli yapıların birbirlerinin tipine dönüştürülmesi de mümkün değildir
my_tick1=(CustomMqlTick)last_tick;// burada derleyici hata dönüşü yapar
|
Bu nedenle tek bir seçenek kalır, o da yapı elemanlarının değerlerini tek tek kopyalamaktır. CustomMqlTick ile aynı tipte olan değerlerin kopyalanması mümkündür.
CustomMqlTick my_tick1,my_tick2;
//--- CustomMqlTick ile aynı tipteki verilerin kopyalanması şu şekilde mümkündür
my_tick2=my_tick1;
//--- CustomMqlTick yapısının nesnelerinden bir dizi oluştur ve değerleri buna yaz
CustomMqlTick arr[2];
arr[0]=my_tick1;
arr[1]=my_tick2;
|
ArrayPrint() fonksiyonu arr[] dizisinin değerini günlükte görüntülemek için çağrılır.
//+------------------------------------------------------------------+
//| Script programı başlatma fonksiyonu |
//+------------------------------------------------------------------+
void OnStart()
{
//--- gömülü MqlTick yapısına benzer bir yapı oluştur
struct CustomMqlTick
{
datetime time; // Son fiyatın güncelleme zamanı
double bid; // Mevcut Satış fiyatı
double ask; // Mevcut Alış fiyatı
double last; // Son işlemin mevcut fiyatı
ulong volume; // Son işlemin hacmi
long time_msc; // Son işlemin güncelleme zamanı
uint flags; // Tik bayrakları
};
//--- son tik fiyatını al
MqlTick last_tick;
CustomMqlTick my_tick1,my_tick2;
//--- MqlTick verilerini CustomMqlTick üzerine kopyalama denemesi
if(SymbolInfoTick(Symbol(),last_tick))
{
//--- ilgisiz basit yapıların kopyalanmasına izin verilmez
//1. my_tick1=last_tick; // derleyici burada bir hata dönüşü yapar
//--- ilgisiz yapılar için tip dönüşümüne de izin verilmez
//2. my_tick1=(CustomMqlTick)last_tick;// derleyici burada bir hata dönüşü yapar
//--- yani, yapı elemanlarını tek tek kopyalamalıyız
my_tick1.time=last_tick.time;
my_tick1.bid=last_tick.bid;
my_tick1.ask=last_tick.ask;
my_tick1.volume=last_tick.volume;
my_tick1.time_msc=last_tick.time_msc;
my_tick1.flags=last_tick.flags;
//--- CustomMqlTick ile aynı tipteki verilerin kopyalanması şu şekilde mümkündür
my_tick2=my_tick1;
//--- CustomMqlTick yapısının nesnelerinden bir dizi oluştur ve değerleri buna yaz
CustomMqlTick arr[2];
arr[0]=my_tick1;
arr[1]=my_tick2;
ArrayPrint(arr);
//--- CustomMqlTick tipli nesneler içeren dizinin değerlerinin görüntülenmesi için örnek
/*
[time] [bid] [ask] [last] [volume] [time_msc] [flags]
[0] 2017.05.29 15:04:37 1.11854 1.11863 +0.00000 1450000 1496070277157 2
[1] 2017.05.29 15:04:37 1.11854 1.11863 +0.00000 1450000 1496070277157 2
*/
}
else
Print("SymbolInfoTick() başarısız, hata = ",GetLastError());
}
|
İkinci örnek aynı soydan iki basit yapının kopyalanmasını göstermektedir. Elimizde Animal (hayvan) yapısından türetilen Cat (kedi) ve Dog (köpek) gibi iki basit yapı olsun. Animal ve Cat nesnelerini (aynı şekilde Animal ve Dog nesnelerini) birbirine kopyalayabiliriz. Ama Cat ve Dog nesneleri aynı soydan (Animal) gelmelerine rağmen birbirlerine kopyalanamaz.
//--- köpekleri tanımlayan yapı
struct Dog: Animal
{
bool hunting; // vahşi tür
};
//--- kedileri tanımlayan yapı
struct Cat: Animal
{
bool home; // evcil tür
};
//--- türetik yapıları oluştur
Dog dog;
Cat cat;
//--- atadan neslinde olana kopyalama yapılabilir (Animal ==> Dog)
dog=some_animal;
dog.swim=true; // köpekler yüzebilir
//--- türetik yapılar birbirlerine kopyalanamaz (Dog != Cat)
cat=dog; // derleyici hata dönüşü yapar
|
Örneğin tam kodu:
//--- hayvanları tanımlayan temel yapı
struct Animal
{
int head; // baş sayısı
int legs; // bacak sayısı
int wings; // kanat sayısı
bool tail; // kuyruk
bool fly; // uçucu
bool swim; // yüzücü
bool run; // koşucu
};
//--- köpekleri tanımlayan yapı
struct Dog: Animal
{
bool hunting; // vahşi tür
};
//--- kedileri tanımlayan yapı
struct Cat: Animal
{
bool home; // evcil tür
};
//+------------------------------------------------------------------+
//| Script programı başlatma fonksiyonu |
//+------------------------------------------------------------------+
void OnStart()
{
//--- temel Animal (hayvan) tipli nesneyi tanımla
Animal some_animal;
some_animal.head=1;
some_animal.legs=4;
some_animal.wings=0;
some_animal.tail=true;
some_animal.fly=false;
some_animal.swim=false;
some_animal.run=true;
//--- türetik nesne tiplerini oluştur
Dog dog;
Cat cat;
//--- atadan neslinde olana kopyalama yapılabilir (Animal ==> Dog)
dog=some_animal;
dog.swim=true; // köpekler yüzebilir
//--- türetik yapılar birbirlerine kopyalanamaz (Dog != Cat)
//cat=dog; // derleyici burada hata dönüşü yapar
//--- ama nesne bileşenleri tek tek kopyalanabilir
cat.head=dog.head;
cat.legs=dog.legs;
cat.wings=dog.wings;
cat.tail=dog.tail;
cat.fly=dog.fly;
cat.swim=false; // kediler yüzemez
//--- neslinde olandan ataya kopyalama yapılabilir
Animal elephant;
elephant=cat;
elephant.run=false;// filler koşamaz
elephant.swim=true;// filler yüzer
//--- Bir dizi oluştur
Animal animals[4];
animals[0]=some_animal;
animals[1]=dog;
animals[2]=cat;
animals[3]=elephant;
//--- sonuçları çıktıla
ArrayPrint(animals);
//--- çalıştırma sonucu
/*
[head] [legs] [wings] [tail] [fly] [swim] [run]
[0] 1 4 0 true false false true
[1] 1 4 0 true false true true
[2] 1 4 0 true false false false
[3] 1 4 0 true false true false
*/
}
|
Basit tipli yapıları kopyalamanın bir diğer yolu bileşimdir. Yapı elemanları aynı bileşimin üyeleri olmalıdır – bkz. bileşim örneği.
Yapı Üyelerine Erişim
Yapılara verilen isimler yeni veri tiplerini temsil eder ve yeni değişkenlerin bildirimi bu tipler ile yapılabilir. Yapılar bir proje içinde yalnızca bir defa bildirilebilir. Yapı üyelerine nokta işlemi (.) kullanılarak erişilebilir.
Örnek:
struct trade_settings
{
double take; // kar sabitleme değerleri
double stop; // koruyucu durdurma fiyatı değeri
uchar slippage; // kabul edilebilir slipaj
};
//--- trade_settings tipinde bir değişken oluştur ve başlat
trade_settings my_set={0.0,0.0,5};
if (input_TP>0) my_set.take=input_TP;
|
yapı ve sınıf alanlarını hizalamak için 'pack' #
Özel pack özelliği, yapı veya sınıf alanlarının hizalanmasını sağlar.
burada n, şu değerlerden biridir: 1, 2, 4, 8 ya da 16. n değeri bulunmayadabilir.
Örnek:
struct pack(sizeof(long)) MyStruct
{
// yapı üyeleri 8 bayt sınırına hizalanacak
};
or
struct MyStruct pack(sizeof(long))
{
// yapı üyeleri 8 bayt sınırına hizalanacak
};
|
Yapılar için varsayılan olarak 'pack(1)' uygulanır. Bu, yapı elemanlarının birbiri ardına hafızaya yerleştirildiği ve yapı büyüklüğünün üyelerinin büyüklüğünün toplamına eşit olduğu anlamına gelir.
Örnek:
//+------------------------------------------------------------------+
//| Script programı başlatma fonksiyonu |
//+------------------------------------------------------------------+
void OnStart()
{
//--- hizasız basit yapı
struct Simple_Structure
{
char c; // sizeof(char)=1
short s; // sizeof(short)=2
int i; // sizeof(int)=4
double d; // sizeof(double)=8
};
//--- basit bir yapı örneği bildir
Simple_Structure s;
//--- her yapı üyesinin boyutunu göster
Print("sizeof(s.c)=",sizeof(s.c));
Print("sizeof(s.s)=",sizeof(s.s));
Print("sizeof(s.i)=",sizeof(s.i));
Print("sizeof(s.d)=",sizeof(s.d));
//--- POD yapısının büyüklüğünün, üyelerinin büyüklüğünün toplamına eşit olduğundan emin ol
Print("sizeof(simple_structure)=",sizeof(simple_structure));
/*
Result:
sizeof(s.c)=1
sizeof(s.s)=2
sizeof(s.i)=4
sizeof(s.d)=8
sizeof(simple_structure)=15
*/
}
|
Bu tür bir hizalamanın uygulandığı üçüncü taraf kütüphaneleriyle (*.DLL) veri alışverişinde bulunurken yapı alanlarının hizalanması gerekebilir.
Hizalamanın nasıl çalıştığını göstermek için bazı örnekler kullanalım. Dört üyeden oluşan hizasız bir yapı uygulayacağız.
//--- hizasız basit yapı
struct Simple_Structure pack() // boyut belirtilmemiş, 1 bayt sınırına hizalama ayarlanacak
{
char c; // sizeof(char)=1
short s; // sizeof(short)=2
int i; // sizeof(int)=4
double d; // sizeof(double)=8
};
//--- basit bir yapı örneği bildir
Simple_Structure s;
|
Yapı alanları şu durumlara göre birbiri ardına hafızaya yerleştirilmelidir: bildiri sırası ve tip boyutu. Yapı boyutu 15'tir, dizilerdeki yapı alanlarına olan öteleme tanımsızdır.

Şimdi aynı yapıyı 4 bayt olarak hizalayarak bildirin ve kodu çalıştırın.
//+------------------------------------------------------------------+
//| Script programı başlatma fonksiyonu |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 4 baytlık hizalama ile basit yapı
struct Simple_Structure pack(4)
{
char c; // sizeof(char)=1
short s; // sizeof(short)=2
int i; // sizeof(int)=4
double d; // sizeof(double)=8
};
//--- basit bir yapı örneği bildir
Simple_Structure s;
//--- her yapı üyesinin boyutunu göster
Print("sizeof(s.c)=",sizeof(s.c));
Print("sizeof(s.s)=",sizeof(s.s));
Print("sizeof(s.i)=",sizeof(s.i));
Print("sizeof(s.d)=",sizeof(s.d));
//--- şimdi, POD yapısının boyutunun, üyelerinin boyutlarının toplamına eşit olmadığından emin olun
Print("sizeof(simple_structure)=",sizeof(simple_structure));
/*
Result:
sizeof(s.c)=1
sizeof(s.s)=2
sizeof(s.i)=4
sizeof(s.d)=8
sizeof(simple_structure)=16 // yapı boyutu değişti
*/
}
|
Yapı boyutu değişti, böylece 4 bayt ve daha fazla olan tüm üyeler, yapının başlangıcından itibaren 4 baytın katları kadar olacak şekilde ötelemeye sahip oldu. Daha küçük üyeler kendi boyut sınırlarına göre hizalanmalıdır (örneğin, 'short' için 2). Görünüşü şu şekildedir (eklenen bayt gri renkte gösterilir).

Bu durumda, s.c üyesinden sonra 1 bayt eklenmiştir, böylece s.s (sizeof(short)==2) alanı 2 bayt sınırına sahip olmuştur ('short' tipi için hizalama).
Dizideki yapının başlangıcına olan öteleme da 4-bayt sınırına hizalanır, diğer bir deyişle Simple_Structure arr[] için a[0], a[1] ve a[n] elemanlarının adresleri 4 baytın katları olacaktır.
4 baytlık hizalamaya ancak farklı üye sırasına sahip benzer tiplerden oluşan iki yapı daha ele alalım. İlk yapıda, üyeler artan tip boyutu sırasında bulunurlar.
//+------------------------------------------------------------------+
//| Script programı başlatma fonksiyonu |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 4 bayt sınırına göre düzenlenmiş basit yapı
struct CharShortInt pack(4)
{
char c; // sizeof(char)=1
short s; // sizeof(short)=2
int i; // sizeof(double)=4
};
//--- basit bir yapı örneği bildir
CharShortInt ch_sh_in;
//--- her yapı üyesinin boyutunu göster
Print("sizeof(ch_sh_in.c)=",sizeof(ch_sh_in.c));
Print("sizeof(ch_sh_in.s)=",sizeof(ch_sh_in.s));
Print("sizeof(ch_sh_in.i)=",sizeof(ch_sh_in.i));
//--- POD yapısının büyüklüğünün, üyelerinin büyüklüğünün toplamına eşit olduğundan emin ol
Print("sizeof(CharShortInt)=",sizeof(CharShortInt));
/*
Result:
sizeof(ch_sh_in.c)=1
sizeof(ch_sh_in.s)=2
sizeof(ch_sh_in.i)=4
sizeof(CharShortInt)=8
*/
}
|
Gördüğümüz üzere, yapı boyutu 8'dir ve iki adet 4 baytlık bloktan oluşur. İlk blok 'char' ve 'short' tipindeki alanları, ikincisi ise 'int' tipindeki alanı içerir.

Şimdi, ilk yapıyı, 'short' tipi üyesinin sona taşınmasıyla sadece alan sırasında farklılık gösteren ikinci yapıya dönüştürelim.
//+------------------------------------------------------------------+
//| Script programı başlatma fonksiyonu |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 4 bayt sınırına göre düzenlenmiş basit yapı
struct CharIntShort pack(4)
{
char c; // sizeof(char)=1
int i; // sizeof(double)=4
short s; // sizeof(short)=2
};
//--- basit bir yapı örneği bildir
CharIntShort ch_in_sh;
//--- her yapı üyesinin boyutunu göster
Print("sizeof(ch_in_sh.c)=",sizeof(ch_in_sh.c));
Print("sizeof(ch_in_sh.i)=",sizeof(ch_in_sh.i));
Print("sizeof(ch_in_sh.s)=",sizeof(ch_in_sh.s));
//--- POD yapısının büyüklüğünün, üyelerinin büyüklüğünün toplamına eşit olduğundan emin ol
Print("sizeof(CharIntShort)=",sizeof(CharIntShort));
/*
Result:
sizeof(ch_in_sh.c)=1
sizeof(ch_in_sh.i)=4
sizeof(ch_in_sh.s)=2
sizeof(CharIntShort)=12
*/
}
|
Yapı içeriği değişmemiş olsa da, üye sırasını değiştirmek yapının boyutunu arttırdı.

Devralınırken hizalama da göz önünde bulundurulmalıdır. Bunu tek 'char' tipi üyesine sahip basit Parent yapısını kullanarak gösterelim. Hizasız yapı boyutu 1'dir.
struct Parent
{
char c; // sizeof(char)=1
};
|
'short' (sizeof(short)=2) tipi üyesini içeren Children alt sınıfını oluşturalım.
struct Children pack(2) : Parent
{
short s; // sizeof(short)=2
};
|
Sonuç olarak, 2 bayta hizalama yapılırken, üyelerinin boyutu 3 olmasına rağmen yapı boyutu 4'e eşittir. Bu örnekte, Parent sınıfına 2 bayt ayrılacaktır, böylece alt sınıfın 'short' alanına erişim 2 bayt ile hizalanmış olacaktır.
Bir MQL5 uygulaması, dosyalar veya akışlar düzeyinde yazarak/okuyarak üçüncü taraf verileriyle etkileşime girerse, yapı üyeleri için belleğin nasıl ayrıldığının bilgisi gereklidir.
Standart Kütüphanenin MQL5\Include\WinAPI dizini WinAPI fonksiyonlarıyla çalışmak için fonksiyonlar içerir. Bu fonksiyonlar, WinAPI ile çalışmak için gereken durumlarda, belirtilen bir hizalama ile yapıları uygular.
offsetof doğrudan pack özniteliği ile ilgili özel bir komuttur. Yapının başından bir üye ötelemesi elde etmemizi sağlar.
//--- Children tipi değişkeni bildir
Children child;
//--- yapının başlangıcından ötelemeleri (ofsetleri) sapta
Print("offsetof(Children,c)=",offsetof(Children,c));
Print("offsetof(Children,s)=",offsetof(Children,s));
/*
Result:
offsetof(Children,c)=0
offsetof(Children,s)=2
*/
|
'final' Şekillendiricisi #
Yapıların bildirimi sırasında 'final' şekillendiricisinin kullanımı, kalıtımı engeller. Yapı üzerinde daha fazla değişikliğe ihtiyaç duyulmuyorsa veya güvenlik gerekçeleriyle izin verilmiyoyarsa, yapıyı bildirirken 'final' şekillendiricisini kullanabilirsiniz. Bu şekilde yapının tüm elemanlarının –kapalı yolla– son şekillerini aldığı varsayılır.
struct settings final
{
//--- Yapı gövdesi
};
struct trade_settings : public settings
{
//--- yapı gövdesi
};
|
Yukarıdaki örnekte de gösterildiği gibi, 'final' şekillendiricisi ile bildirilmiş bir yapıdan kalıtım yapılmak istendiğinde, derleyici hata dönüşü yapacaktır:
cannot inherit from 'settings' as it has been declared as 'final'
see declaration of 'settings'
|
Sınıflar #
Sınıflar aşağıda belirtilen maddeler açısından yapılardan ayrılır:
- class anahtar sözcüğü bildirimde kullanılır;
- Aksi belirtilmemişse, varsayılan olarak tüm sınıf üyeleri private erişim belirtecine sahiptir. Aksi belirtilmemişse, yapıların veri üyeleri 'public' erişim belirtecine sahiptir;
- Sınıf içinde bildirilen bir sanal fonksiyon olmasa bile sınıf üyeleri her zaman bir sanal fonksiyonlar tablosuna sahiptir. Yapılar sanal fonksiyonlara sahip olamaz;
- new operatörü sınıf nesnelerine uygulanabilir ama yapılara uygulanamaz;
- sınıflar, diğer sınıflardan kalıtsal yolla oluşturulabilir. Aynı şekilde yapılar da sadece yapılardan kalıtsal olarak oluşturulabilir.
Sınıflar ve yapılar açık yapıcı ve yıkıcı fonksiyonlara sahip olabilirler. Eğer yapı fonksiyon açık şekilde tanımlanmışsa, yapı veya sınıf değişkeninin başlatma sırası kullanılarak başlatılması imkansızdır.
Örnek:
struct trade_settings
{
double take; // kar sabitleme değerleri
double stop; // koruyucu durdurma fiyatı değeri
uchar slippage; // kabul edilebilir slipaj
//--- Yapıcı
trade_settings() { take=0.0; stop=0.0; slippage=5; }
//--- Yıkıcı
~trade_settings() { Print("Bu, son"); }
};
//--- Derleyici başlatmanın imkansız olduğunu belirten bir hata mesajı oluşturacaktır
trade_settings my_set={0.0,0.0,5};
|
Yapıcı ve Yıkıcı Fonksiyonlar
Yapıcı, bir yapı veya sınıf nesnesi oluşturulduğunda otomatik olarak çağrılan özel bir fonksiyondur. Genellikle sınıf üyelerini başlatmak için kullanılır. Aynı uygulamalar yapılar için de geçerli olacağından, bundan sonra aksi belirtilmedikçe sadece sınıflar hakkında konuşacağız. Yapıcının ismi sınıf ismi ile örtüşmelidir. Yapıcının bir dönüş tipi yoktur (void tipini belirtebilirsiniz).
Tanımlanmış sınıf üyeleri – dizeler, dinamik diziler ve başlatma gerektiren nesneler – bir yapıcı olup olmadığına bakılmaksızın her durumda başlatılır.
Her sınıf parametre sayısı açısından veya başlatma listesi açısından farklı olan birden fazla yapıcı fonksiyon içerebilir. Parametrelerinin belirtilmesi gereken yapıcılara parametrik yapıcı denir.
Parametresiz olarak bildirilen yapıcılar ön-tanımlı yapıcılardır. Eğer sınıf içinde hiç yapıcı bildirilmemişse derleyici otomatik olarak bir ön-tanımlı yapıcı oluşturacaktır.
//+------------------------------------------------------------------+
//| Tarihle çalışmak için bir sınıf |
//+------------------------------------------------------------------+
class MyDateClass
{
private:
int m_year; // Yıl
int m_month; // Ay
int m_day; // Ayın günü
int m_hour; // Günün saati
int m_minute; // Dakikalar
int m_second; // Saniyeler
public:
//--- Ön tanımlı yapıcı
MyDateClass(void);
//--- Parametrik yapıcı
MyDateClass(int h,int m,int s);
};
|
Yapıcı fonksiyonlar sınıf tarifinde bildirilebilir ve gövdeleri daha sonra tanımlanabilir. Örneğin MyDateClass'ın iki yapıcısı, şu yolla tanımlanabilir:
//+------------------------------------------------------------------+
//| Ön tanımlı yapıcı |
//+------------------------------------------------------------------+
MyDateClass::MyDateClass(void)
{
//---
MqlDateTime mdt;
datetime t=TimeCurrent(mdt);
m_year=mdt.year;
m_month=mdt.mon;
m_day=mdt.day;
m_hour=mdt.hour;
m_minute=mdt.min;
m_second=mdt.sec;
Print(__FUNCTION__);
}
//+------------------------------------------------------------------+
//| Parametrik yapıcı |
//+------------------------------------------------------------------+
MyDateClass::MyDateClass(int h,int m,int s)
{
MqlDateTime mdt;
datetime t=TimeCurrent(mdt);
m_year=mdt.year;
m_month=mdt.mon;
m_day=mdt.day;
m_hour=h;
m_minute=m;
m_second=s;
Print(__FUNCTION__);
}
|
Ön-tanımlı yapıcının içindeki tüm sınıf üyeleri TimeCurrent() fonksiyonu ile doldurulur. Parametrik yapıcı içindeyse sadece saat verileri kullanılır. Diğer sınıf üyeleri (m_year, m_month ve m_day) otomatik olarak mevcut tarihle başlatılır.
Ön tanımlı yapıcı kendi sınıfı içindeki bir nesne dizisi başlatılırken özel bir amaca sahiptir. Tüm parametreleri ön-tanımlı değerler alan yapılar ön-tanımlı yapı değildir. Bir örnek:
//+------------------------------------------------------------------+
//| Ön-tanımlı yapıcıya sahip bir sınıf |
//+------------------------------------------------------------------+
class CFoo
{
datetime m_call_time; // Son nesne çağrısının zamanı
public:
//--- Ön tanımlı bir parametreye sahip olan yapıcı, bir ön tanımlı yapıcı değildir
CFoo(const datetime t=0){m_call_time=t;};
//--- Kopya yapıcı
CFoo(const CFoo &foo){m_call_time=foo.m_call_time;};
string ToString(){return(TimeToString(m_call_time,TIME_DATE|TIME_SECONDS));};
};
//+------------------------------------------------------------------+
//| Script programı başlatma fonksiyonu |
//+------------------------------------------------------------------+
void OnStart()
{
// CFoo foo; // Bu varyant kullanılamaz - bir ön tanımlı yapıcı ayarlanmamış
//--- CFoo nesnesini oluşturmak için seçenekler
CFoo foo1(TimeCurrent()); // Bir parametrik yapıcının açık çağrısı
CFoo foo2(); // Ön tanımlı parametreye sahip bir parametrik yapıcının açık çağrısı
CFoo foo3=D'2009.09.09'; // Bir parametrik yapıcının gizli çağrısı
CFoo foo40(foo1); // Kopya yapıcının açık çağrısı
CFoo foo41=foo1; // Kopya yapıcının kapalı çağrısı
CFoo foo5; // Bir ön tanımlı yapıcının açık çağrısı ( eğer hiç ön tanımlı yapıcı yok sa,
// o zaman ön tanımlı değere sahip bir parametrik yapıcı çağrılır)
//--- CFoo işaretçilerinin alınması için muhtemel seçenekler
CFoo *pfoo6=new CFoo(); // Nesnenin dinamik olarak oluşturulması ve buna atanan bir işaretçinin alınması
CFoo *pfoo7=new CFoo(TimeCurrent());// Dinamik nesne oluşturmak için bir diğer seçenek
CFoo *pfoo8=GetPointer(foo1); // şimdi pfoo8, foo1 nesnesini işaretliyor
CFoo *pfoo9=pfoo7; // pfoo9 ve pfoo7 aynı nesneye işaret ediyor
// CFoo foo_array[3]; // Bu seçenek kullanılamaz - bir ön tanımlı yapıcı belirtilmemiş
//--- m_call_time değerini göster
Print("foo1.m_call_time=",foo1.ToString());
Print("foo2.m_call_time=",foo2.ToString());
Print("foo3.m_call_time=",foo3.ToString());
Print("foo4.m_call_time=",foo4.ToString());
Print("foo5.m_call_time=",foo5.ToString());
Print("pfoo6.m_call_time=",pfoo6.ToString());
Print("pfoo7.m_call_time=",pfoo7.ToString());
Print("pfoo8.m_call_time=",pfoo8.ToString());
Print("pfoo9.m_call_time=",pfoo9.ToString());
//--- Dinamik olarak oluşturulmuş dizileri sil
delete pfoo6;
delete pfoo7;
//delete pfoo8; // pfoo8, otomatik olarak foo1 oluşturulmuş nesnesini gösterdiğinden, bunu açıkça silmek zorunda değilsiniz
//delete pfoo9; // pfoo7 ile aynı nesneye işaret ettiğinden pfoo9'u açıkça silmek zorunda değilsiniz.
}
|
Bu dizeleri yorumsuz bırakırsanız
//CFoo foo_array[3]; // Bu varyant kullanılamaz - ön tanımlı bir yapıcı ayarlanmamış
|
veya
//CFoo foo_dyn_array[]; // Bu varyant kullanılamaz - ön tanımlı bir yapıcı ayarlanmamış
|
Bu durumda derleyici, "ön tanımlı yapıcı ayarlanmamış" şeklinde bir hata verecektir.
Eğer bir sınıf kullanıcı tanımlı bir yapıcıya sahipse derleyici tarafından ön tanımlı bir yapıcı oluşturulmaz. Bu demektir ki, eğer sınıfın içinde bir ön tanımlı yapıcı değil, bir parametrik yapıcı bildirilmişse bu sınıfın nesnelerinin dizilerini bildiremezsiniz. Derleyici bu betik için bir hata dönüşü yapacaktır:
//+------------------------------------------------------------------+
//| Ön tanımlı yapıcısı olmayan bir sınıf |
//+------------------------------------------------------------------+
class CFoo
{
string m_name;
public:
CFoo(string name) { m_name=name;}
};
//+------------------------------------------------------------------+
//| Script programı başlatma fonksiyonu |
//+------------------------------------------------------------------+
void OnStart()
{
//--- Derleme sırasında "ön tanımlı yapıcı tanımlanmamış" hatasını al
CFoo badFoo[5];
}
|
Bu örnekte, CFoo sınıfı bir parametrik yapıcıya sahiptir – böyle durumlarda derleyici, derleme esnasında otomatik olarak bir ön tanımlı yapıcı oluşturmaz. Aynı zamanda, bir nesne dizisi bildirdiğinizde tüm nesnelerin otomatik olarak oluşturulması ve başlatılması gerektiği varsayılır. Bir nesnenin otomatik olarak başlatılması sırasında, bir ön tanımlı yapıcı çağrılması gerekir ama ön tanımlı yapıcı açıkça bildirilmedikçe veya derleyici tarafından otomatik olarak oluşturulmadıkça böyle bir nesneyi oluşturmak imkansızdır. Bu yüzden derleyici, derleme sırasında bir hata oluşturur.
Bir nesneyi, bir yapı aracılığıyla başlatmak için özel bir sözdizim mevcuttur. Bir sınıf veya yapı için, yapı başlatıcıları (başlatma için özel yapılar) başlatma listesinde belirlenebilir.
Bir başlatma listesi, yapıcının parametre listesi sonundaki iki noktanın ardından gelen, virgül ile ayrılmış bir başlatıcılar listesidir; gövdeden önce gelir (açılış parantezinin öncesinde). Birkaç gereksinimi vardır:
- Başlatma listeleri sadece yapıcılarda kullanılabilir;
- Ebeveyn üyeler başlatma listesinin içinde başlatılamaz;
- Başlatma listesi fonksiyon tanımından (uygulamasından) önce gelmelidir.
Burada, sınıf üyelerinin başlatılması için birkaç yapıcıya örnek verilmiştir.
//+------------------------------------------------------------------+
//| Bir karakterin ismini saklaması için bir sınıf |
//+------------------------------------------------------------------+
class CPerson
{
string m_first_name; // İlk isim
string m_second_name; // Soy isim
public:
//--- Boş bir ön tanımlı yapıcı
CPerson() {Print(__FUNCTION__);};
//--- Bir parametrik yapıcı
CPerson(string full_name);
//--- Başlatma listeli bir yapıcı
CPerson(string surname,string name): m_second_name(surname), m_first_name(name) {};
void PrintName(){PrintFormat("İsim=%s Soyisim=%s",m_first_name,m_second_name);};
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CPerson::CPerson(string full_name)
{
int pos=StringFind(full_name," ");
if(pos>=0)
{
m_first_name=StringSubstr(full_name,0,pos);
m_second_name=StringSubstr(full_name,pos+1);
}
}
//+------------------------------------------------------------------+
//| Script programı başlatma fonksiyonu |
//+------------------------------------------------------------------+
void OnStart()
{
//--- Bir hata al "ön tanımlı yapıcı tanımlanmamış"
CPerson people[5];
CPerson Tom="Tom Sawyer"; // Tom Sawyer
CPerson Huck("Huckleberry","Finn"); // Huckleberry Finn
CPerson *Pooh = new CPerson("Winnie","Pooh"); // Winnie the Pooh
//--- Çıktı değerleri
Tom.PrintName();
Huck.PrintName();
Pooh.PrintName();
//--- Dinamik olarak oluşturulmuş nesneleri sil
delete Pooh;
}
|
Bu durumda CPerson sınıfının üç yapıcısı vardır:
- Bu sınıfın nesnelerinden bir dizi oluşturmayı sağlayan açık bir ön tanımlı yapıcı;
- Bütün ismi bir parametre olarak alan ve sonra bunu, bulunan alanlara göre ilk isim ve soy isim olarak bölen tek parametreli bir yapıcı;
- Bir başlatma listesi içeren iki parametreli bir yapıcı. Başlatıcılar - m_second_name(surname) and m_first_name(name).
Liste ile başlatma işleminin atamanın yerini değiştirdiğini not edin. Tekil üyeler şu şekilde başlatılmalıdır:
class_member (ifadelerden oluşan bir liste)
|
Başlatma listesinde üyeler herhangi şekilde sıralanabilir ama bütün sınıf üyeleri duyuruldukları sıra ile başlatılır. Bu demektir ki, üçüncü yapıcıda ilk olarak m_first_name üyesi başlatılır çünkü ilk o bildirilmiştir ve ancak ondan sonra m_second_name başlatılır. Bazı üyelerin başlatılmasının diğer sınıf üyelerinin değerlerine bağlı olduğu durumlarda, bu hesaba katılmalıdır.
Eğer temel sınıf içinde bir ön tanımlı yapıcı bildirilmişse ve parametreli olarak bir veya birden fazla yapıcı bildirilmişse, her zaman başlatma listesindeki temel sınıf yapıcılarından birini çağırmalısınız. Bunlar, listenin sıradan üyeleri gibi virgülle geçer ve başlatma listesinin nerede konumlandığına bakılmaksızın, nesnenin başlatılması sırasında ilk olarak çağrılır.
//+------------------------------------------------------------------+
//| Temel sınıf |
//+------------------------------------------------------------------+
class CFoo
{
string m_name;
public:
//--- Başlatma listeli bir yapıcı
CFoo(string name) : m_name(name) { Print(m_name);}
};
//+------------------------------------------------------------------+
//| CFoo sınıfından türetilen sınıf |
//+------------------------------------------------------------------+
class CBar : CFoo
{
CFoo m_member; // Bir sınıf üyesi ebeveynin nesnesidir
public:
//--- Başlatma listesindeki bir ön tanımlı yapıcı ebeveyn yapıcısını çağırır
CBar(): m_member(_Symbol), CFoo("CBAR") {Print(__FUNCTION__);}
};
//+------------------------------------------------------------------+
//| Script programı başlatma fonksiyonu |
//+------------------------------------------------------------------+
void OnStart()
{
CBar bar;
}
|
Bu örnekte, bar nesnesini oluştururken bir ön tanımlı yapıcı CBar() çağrılacaktır. Bunun için önce ebeveyn CFoo için bir yapıcı çağrılır ve ardından m_member sınıf üyesi gelir.
Yıkıcı, bir sınıf nesnesi yok edildiğinde çağrılan özel bir fonksiyondur. Yıkıcının ismi bir sınıf ismi gibi tilde işareti ile (~) yazılır. Sonlandırma gerektiren dizgiler, dinamik diziler ve nesneler, yıkıcının varlığından bağımsız olarak sonlandırılır. Eğer bir yıkıcı varsa, o zaman bu eylemler yıkıcı çağrıldıktan sonra gerçekleştirilecektir.
Yıkıcılar, virtual anahtar sözcüğü ile bildirilmiş olup olmadıklarına bakılmaksızın daima sanaldır.
Sınıf Yöntemlerini Tanımlamak
Sınıf fonksiyon-yöntemleri sınıf içinde veya dışında tanımlanabilir. Eğer yöntem sınıf içinde tanımlanmışsa, gövde hemen yöntemin ardından gelir.
Örnek:
class CTetrisShape
{
protected:
int m_type;
int m_xpos;
int m_ypos;
int m_xsize;
int m_ysize;
int m_prev_turn;
int m_turn;
int m_right_border;
public:
void CTetrisShape();
void SetRightBorder(int border) { m_right_border=border; }
void SetYPos(int ypos) { m_ypos=ypos; }
void SetXPos(int xpos) { m_xpos=xpos; }
int GetYPos() { return(m_ypos); }
int GetXPos() { return(m_xpos); }
int GetYSize() { return(m_ysize); }
int GetXSize() { return(m_xsize); }
int GetType() { return(m_type); }
void Left() { m_xpos-=SHAPE_SIZE; }
void Right() { m_xpos+=SHAPE_SIZE; }
void Rotate() { m_prev_turn=m_turn; if(++m_turn>3) m_turn=0; }
virtual void Draw() { return; }
virtual bool CheckDown(int& pad_array[]);
virtual bool CheckLeft(int& side_row[]);
virtual bool CheckRight(int& side_row[]);
};
|
SetRightBorder(int border)'dan, Draw()'a kadar fonksiyonlar, doğrudan CTetrisShape sınıfının içinde tanımlanırlar.
CTetrisShape() yapıcısı ve CheckDown(int& pad_array[]), CheckLeft(int& side_row[]) ve CheckRight(int& side_row[]) yöntemleri sadece sınıf içinde tanımlanırlar ama henüz tanımlanmamış durumdadırlar. Bu fonksiyonların tanımları daha ilerde kodda yer alacaktır. Yöntemi sınıf dışında tanımlamak için kapsam çözünürlük operatörü kullanılır (sınıf ismi kapsam olarak kullanılır).
Örnek:
//+------------------------------------------------------------------+
//| Temel sınıfın yapıcısı |
//+------------------------------------------------------------------+
void CTetrisShape::CTetrisShape()
{
m_type=0;
m_ypos=0;
m_xpos=0;
m_xsize=SHAPE_SIZE;
m_ysize=SHAPE_SIZE;
m_prev_turn=0;
m_turn=0;
m_right_border=0;
}
//+------------------------------------------------------------------+
//| Aşağı hareket kabiliyetinin kontrol edilmesi (çubuk ve küp için) |
//+------------------------------------------------------------------+
bool CTetrisShape::CheckDown(int& pad_array[])
{
int i,xsize=m_xsize/SHAPE_SIZE;
//---
for(i=0; i<xsize; i++)
{
if(m_ypos+m_ysize>=pad_array[i]) return(false);
}
//---
return(true);
}
|
Public, Protected ve Private Erişim Şekillendiricileri
Yeni bir sınıf geliştirirken üyelere dışarıdan erişimin sınırlanması tavsiye edilir. Bunun için private veya protected anahtar sözcükleri kullanılır. İlk durumda gizli verilere sadece aynı sınıfın içindeki yöntemler erişebilir. Eğer protected anahtar sözcüğü kullanılmışsa, gizli verilere kalıtımsal türetik sınıfların yöntemleri de erişebilecektir. Aynı yöntem sınıf yöntemlerine yapılacak erişimi engellemek için de kullanılabilir.
Bir sınıfın üyelerine ve/veya yöntemlerine erişimi tamamen açmanız gerekiyorsa public anahtar sözcüğünü kullanın.
Örnek:
class CTetrisField
{
private:
int m_score; // Skor
int m_ypos; // Şekillerin mevcut konumları
int m_field[FIELD_HEIGHT][FIELD_WIDTH]; // Kuyu matrisi
int m_rows[FIELD_HEIGHT]; // Kuyu satırlarının numaralanması
int m_last_row; // Son boş satır
CTetrisShape *m_shape; // Tetris şekli
bool m_bover; // Oyun bitti
public:
void CTetrisField() { m_shape=NULL; m_bover=false; }
void Init();
void Deinit();
void Down();
void Left();
void Right();
void Rotate();
void Drop();
private:
void NewShape();
void CheckAndDeleteRows();
void LabelOver();
};
|
public: anahtar sözcüğünden sonra (ve bir sonraki erişim belirtecinden önce) bildirilen her sınıf üyesi ve yöntemi, programın sınıfa yapacağı her referansta kullanılabilir olacaktır. Bunlar örnek içinde şu üyelere karşılık gelir: CTetrisField(), Init(), Deinit(), Down(), Left(), Right(), Rotate() ve Drop() fonksiyonları.
private: anahtar sözcüğünden sonra (ve bir sonraki erişim belirtecinden önce) bildirilen her sınıf üyesi ve yöntemi, sadece bu sınıfın üyeleri-fonksiyonları için kullanılabilir. Erişim belirteçleri daima iki nota (:) ile sonlandırılır ve sınıf tanımında defalarca görülebilir.
protected: erişim belirteci sonrasında bildirilen tüm sınıf üyeleri (bir sonraki erişim belirtecine kadar), yalnızca bu sınıfın üye fonksiyonları ve bu sınıfın nesillerinin üye fonksiyonları için kullanılabilir. Dışarıdan private ve protected belirteçleri olan üyelere erişmeye çalışırken derleme aşamasında hata alınacaktır. Örnek:
class A
{
protected:
//--- kopya operatörü yalnızca A sınıfı ve nesillerinde bulunur
void operator=(const A &)
{
}
};
class B
{
//--- A sınıfı nesnesi bildirildi
A a;
};
//+------------------------------------------------------------------+
//| Script programı başlatma fonksiyonu |
//+------------------------------------------------------------------+
void OnStart()
{
//--- iki B tipi değişken bildir
B b1, b2;
//--- bir nesneyi diğerine kopyalamaya çalış
b2=b1;
}
|
Bu kodu derlerken, bir hata mesajı alınacaktır - uzak kopya operatörü çağrısı:
attempting to reference deleted function 'void B::operator=(const B&)' trash3.mq5 32 6
|
Aşağıdaki ikinci dizge daha ayrıntılı bir açıklama sağlar - B sınıfındaki kopya operatörü, A sınıfının kullanılamayan kopya operatörü çağrıldığından açıkça silinmiştir:
function 'void B::operator=(const B&)' was implicitly deleted because it invokes inaccessible function 'void A::operator=(const A&)'
|
Temel sınıfın üyelerine yapılacak erişim, türetilmiş sınıflardaki kalıtım sırasında yeniden tanımlanabilir.
'delete' belirteci
delete belirteci, kullanılamayan sınıf üye fonksiyonlarını işaretler. Bu, eğer program açıkça veya dolaylı olarak böyle bir fonksiyona atıfta bulunuyorsa, derleme aşamasında çoktan hata alınacağı anlamına gelir. Örneğin, bu belirteç, bir alt sınıfta üst yöntemlerin kullanılamamasını sağlar. Fonksiyonu, eğer üst sınıfın özel alanında bildirirsek (private bölümündeki bildirimler), aynı sonuç elde edilebilir. Burada, delete kullanmak, kodu nesiller seviyesinde daha okunabilir ve yönetilebilir hale getirir.
class A
{
public:
A(void) {value=5;};
double GetValue(void) {return(value);}
private:
double value;
};
class B: public A
{
double GetValue(void)=delete;
};
//+------------------------------------------------------------------+
//| Script programı başlatma fonksiyonu |
//+------------------------------------------------------------------+
void OnStart()
{
//--- A tipi değişkeni bildir
A a;
Print("a.GetValue()=", a.GetValue());
//--- B tipi değişkenden değer elde et
B b;
Print("b.GetValue()=", b.GetValue()); // derleyici bu dizgede bir hata göstermektedir
}
|
Derleyici mesajı:
attempting to reference deleted function 'double B::GetValue()'
function 'double B::GetValue()' was explicitly deleted here
|
'delete' belirteci, otomatik dönüşümün veya kopya yapıcısının devre dışı bırakılmasına olanak tanır (aksi takdirde private bölümünde de gizlenmesi gerekirdi). Örnek:
class A
{
public:
void SetValue(double v) {value=v;}
//--- int tipi cağrıyı devre dışı bırak
void SetValue(int) = delete;
//--- kopya operatörünü devre dışı bırak
void operator=(const A&) = delete;
private:
double value;
};
//+------------------------------------------------------------------+
//| Script programı başlatma fonksiyonu |
//+------------------------------------------------------------------+
void OnStart()
{
//--- iki A tipi değişken bildir
A a1, a2;
a1.SetValue(3); // hata!
a1.SetValue(3.14); // TAMAM
a2=a1; // hata!
}
|
Derleme sırasında şu hata mesajlarını almaktayız:
attempting to reference deleted function 'void A::SetValue(int)'
function 'void A::SetValue(int)' was explicitly deleted here
attempting to reference deleted function 'void A::operator=(const A&)'
function 'void A::operator=(const A&)' was explicitly deleted here
|
'final' Şekillendiricisi #
Sınıfın bildirimi sırasında 'final' şekillendiricisinin kullanımı, kalıtımı engeller. Sınıf üzerinde daha fazla değişikliğe ihtiyaç duyulmuyorsa veya güvenlik gerekçeleriyle izin verilmiyorsa, sınıf bildiriminde 'final' şekillendiricisini kullanın. Bu şekilde sınıfın tüm elemanlarının –kapalı yolla– son şekillerini aldığı varsayılır.
class CFoo final
{
//--- Sınıf gövdesi
};
class CBar : public CFoo
{
//--- Sınıf gövdesi
};
|
Yukarıdaki örnekte de gösterildiği gibi, 'final' şekillendiricisi ile bildirilmiş bir sınıftan kalıtım yapılmak istendiğinde derleyici hata dönüşü yapacaktır:
cannot inherit from 'CFoo' as it has been declared as 'final'
see declaration of 'CFoo'
|
Birleşimler (union) #
Birleşim, aynı bellek alanını paylaşan birkaç değişkenden oluşan özel bir veri türüdür. Bu nedenle, birleşim aynı bit dizisini iki (veya daha fazla) farklı yolla yorumlama yeteneği sağlar. Birleşim bildirimi, yapı bildirimine benzer ve union anahtar kelimesiyle başlar.
union LongDouble
{
long long_value;
double double_value;
};
|
Yapının aksine, çeşitli birleşim üyeleri aynı hafıza alanına aittir. Bu örnekte, LongDouble birleşimi, aynı bellek alanını paylaşan long ve double tipleriyle bildirilmektedir. long_value ve double_value değişkenleri çakıştığından (bellekte), birleşim deposunu aynı anda bir long tamsayı değeri ve bir double gerçek değeri yapmanın mümkün olmadığını unutmayın (bir yapıdan farklı olarak). Diğer taraftan, bir MQL5 programı, birleşimde bulunan verileri herhangi bir zamanda bir tamsayı (long) veya gerçek (double) değer olarak işleyebilir. Bu nedenle, birleşim aynı veri sırasını temsil etmek için iki (veya daha fazla) seçenek almaya izin verir.
Birleşim bildirimi sırasında, derleyici otomatik olarak değişken birleşimi içinde en büyük tipi (hacme göre) depolamak için yeterli bellek alanını ayırır. Aynı sözdizimi, birleşim elemanına erişim için yapılarda olduğu gibi kullanılır - nokta operatörü.
union LongDouble
{
long long_value;
double double_value;
};
//+------------------------------------------------------------------+
//| Script programı başlatma fonksiyonu |
//+------------------------------------------------------------------+
void OnStart()
{
//---
LongDouble lb;
//--- geçersiz -nan(ind) numarasını alın ve görüntüleyin
lb.double_value=MathArcsin(2.0);
printf("1. double=%f integer=%I64X",lb.double_value,lb.long_value);
//--- en büyük normalleştirilmiş değer (DBL_MAX)
lb.long_value=0x7FEFFFFFFFFFFFFF;
printf("2. double=%.16e integer=%I64X",lb.double_value,lb.long_value);
//--- en küçük pozitif normalleştirilmiş değer (DBL_MIN)
lb.long_value=0x0010000000000000;
printf("3. double=%.16e integer=%.16I64X",lb.double_value,lb.long_value);
}
/* Execution result
1. double=-nan(ind) integer=FFF8000000000000
2. double=1.7976931348623157e+308 integer=7FEFFFFFFFFFFFFF
3. double=2.2250738585072014e-308 integer=0010000000000000
*/
|
Birleşimler, programın aynı bellek verilerini farklı şekillerde yorumlamasına izin verdiğinden, genellikle alışılmadık bir tip dönüşümü gerektiğinde kullanılır.
Birleşimler kalıtım'da yer alamazlar ve aynı zamanda doğası gereği statik üyelere sahip olamazlar. Diğer tüm yönleriyle, union, tüm üyeleri sıfır ötelemeye (ofsete) sahip bir yapı gibi davranır. Aşağıdaki tipler birleşim üyesi olamazlar:
Sınıflara benzer şekilde birleşim, yöntemlerin yanı sıra yapıcı ve yıkıcılara da sahip olabilir. Varsayılan olarak, birleşim üyeleri public erişim tipindedir. Özel elemanlar oluşturmak için private anahtar kelimesini kullanın. Tüm bu olasılıklar, color tipindeki bir rengin ARGB'ye nasıl dönüştürüleceğini (ColorToARGB() fonksiyonunun yaptığı gibi) gösteren örnekte sunulmaktadır.
//+------------------------------------------------------------------+
//| color(BGR)'ın ARGB'ye dönüşümü için birleşim |
//+------------------------------------------------------------------+
union ARGB
{
uchar argb[4];
color clr;
//--- yapıcılar
ARGB(color col,uchar a=0){Color(col,a);};
~ARGB(){};
//--- genele açık yöntemler
public:
uchar Alpha(){return(argb[3]);};
void Alpha(const uchar alpha){argb[3]=alpha;};
color Color(){ return(color(clr));};
//--- Özel yöntemler
private:
//+------------------------------------------------------------------+
//| alfa kanalı değerini ve rengini ayarla |
//+------------------------------------------------------------------+
void Color(color col,uchar alpha)
{
//--- clr üyesinin rengini ayarla
clr=col;
//--- Alfa bileşen değerini ayarla - opaklık seviyesi
argb[3]=alpha;
//--- R ve B bileşenlerinin baytlarını değiş tokuş et (Kırmızı ve Mavi)
uchar t=argb[0];argb[0]=argb[2];argb[2]=t;
};
};
//+------------------------------------------------------------------+
//| Script programı başlatma fonksiyonu |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 0x55, 55/255=21.6% anlamına gelir (0%, tamamen saydamdır)
uchar alpha=0x55;
//--- color tipi 0x00BBGGRR olarak temsil edilir
color test_color=clrDarkOrange;
//--- ARGB birleşiminden gelen bayt değerleri burada kabul edilir
uchar argb[];
PrintFormat("0x%.8X - %s, BGR=(%s) için 'color' tipinin nasıl göründüğü belirtilmektedir",
test_color,ColorToString(test_color,true),ColorToString(test_color));
//--- ARGB tipi 0x00RRGGBB olarak temsil edilir, RR ve BB bileşenleri yer değiştirmiştir
ARGB argb_color(test_color);
//--- bayt dizisini kopyala
ArrayCopy(argb,argb_color.argb);
//--- ARGB temsilinde görünümün nasıl olduğu
PrintFormat("0x%.8X - alfa kanalı=0x%.2x, ARGB=(%d,%d,%d,%d) ile ARGB temsili",
argb_color.clr,argb_color.Alpha(),argb[3],argb[2],argb[1],argb[0]);
//--- opaklık düzeyini ekle
argb_color.Alpha(alpha);
//--- ARGB'yi 'color' tipi olarak tanımlamayı dene
Print("color olarak ARGB=(",argb_color.clr,") alfa kanalı=",argb_color.Alpha());
//--- bayt dizisini kopyala
ArrayCopy(argb,argb_color.argb);
//--- ARGB temsilinde görünümün nasıl olduğu
PrintFormat("0x%.8X - alfa kanalı=0x%.2x, ARGB=(%d,%d,%d,%d) ile ARGB temsili",
argb_color.clr,argb_color.Alpha(),argb[3],argb[2],argb[1],argb[0]);
//--- ColorToARGB() fonksiyonu sonuçları ile kontrol edin
PrintFormat("0x%.8X - ColorToARGB(%s,0x%.2x) nin sonucu",ColorToARGB(test_color,alpha),
ColorToString(test_color,true),alpha);
}
/* Gerçekleşim sonucu
0x00008CFF - clrDarkOrange için 'color' tipinin nasıl göründüğü belirtilmektedir, BGR=(255,140,0)
0x00FF8C00 - alfa kanalı=0x00, ARGB=(0,255,140,0) ile ARGB temsili
color olarak ARGB=(0,140,255) alfa kanalı=85
0x55FF8C00 - alfa kanalı=0x55, ARGB=(85,255,140,0) ile ARGB temsili
0x55FF8C00 - ColorToARGB(clrDarkOrange,0x55)'nin sonucu
*/
|
Arayüzler #
Arayüzler sınıflar tarafından daha sonra kullanılmak üzere belirli bir işlevselliği tanımlamaya yarar. Aslında bunlar üyeleri olmayan sınıflardır yapıcı ve yıkıcı fonksiyonları içeremezler. Arayüzlerin bünyesinde bildirimi yapılan tüm yöntemler –açık tanıma sahip olmasalar bile– sanal yöntemlerdir.
Arayüzler "interface" anahtar sözcüğü ile tanımlanırlar. Örnek:
//--- Hayvanları açıklamak için temel arayüz
interface IAnimal
{
//--- arayüzün yöntemleri varsayılan olarak genel erişime açık
void Sound(); // hayvanın çıkardığı ses
};
//+------------------------------------------------------------------+
//| CCat sınıfı IAnimal arayüzünden türetilmiştir |
//+------------------------------------------------------------------+
class CCat : public IAnimal
{
public:
CCat() { Print("Kedi doğdu"); }
~CCat() { Print("Kedi öldü"); }
//--- IAnimal arayüzündeki Sound yönteminin uygulanması
void Sound(){ Print("miyav"); }
};
//+------------------------------------------------------------------+
//| CDog sınıfı IAnimal arayüzünden türetilmiştir |
//+------------------------------------------------------------------+
class CDog : public IAnimal
{
public:
CDog() { Print("Köpek doğdu"); }
~CDog() { Print("Köpek öldü"); }
//--- IAnimal arayüzündeki Sound yönteminin uygulanması
void Sound(){ Print("hav"); }
};
//+------------------------------------------------------------------+
//| Script programı başlatma fonksiyonu |
//+------------------------------------------------------------------+
void OnStart()
{
//--- IAnimal tipi nesneler için bir işaretçi dizisi
IAnimal *animals[2];
//--- IAnimal 'dan çocuk sınıfların oluşturulması ve bunların işaretçilerinin bir diziye yüklenmesi
animals[0]=new CCat;
animals[1]=new CDog;
//--- Her çocuk sınıf için IAnimal arayüzünün Sound() yöntemini çağır
for(int i=0;i<ArraySize(animals);++i)
animals[i].Sound();
//--- Nesnelerin silinmesi
for(int i=0;i<ArraySize(animals);++i)
delete animals[i];
//--- Çalıştırma sonuçları
/*
Kedi doğdu
Köpek doğdu
miyav
hav
Kedi öldü
Köpek öldü
*/
}
|
Soyut sınıflar gibi arayüzler de kalıtım olmadan kullanılamazlar. Sadece diğer arayüzlerden türetilebilirler ve ilgili sınıflara ebeveynlik yapabilirler. Arayüzler her zaman genel görünürlüğe sahiptir.
Bildirimleri sınıfların veya yapıların bildirimlerine dahil edilemez ama arayüzün bir işaretçisi void * tipli bir değişkende saklanabilir. Genel olarak, sınıf nesnesi işaretçileri void * tipli değişkenlerde saklanabilir. void * işaretçisini belli bir sınıf nesnesinin işaretçisine dönüştürmek için dynamic_cast operatörünü kullanın. Dönüşüm mümkün olmadığında, dynamic_cast işlemi NULL ifadesi ile sonuçlanır.
Ayrıca bakınız
Nesne Yönelimli Programlama