> DEĞİŞKENLERİN TANIMLANMASI : >> 'default-initialization' : "int x;", "int a[10];" ve "Myclass mx;" şeklinde yapılan hayata getirme biçimidir. >>> Otomatik ömürlü aritmetik türden değişkenleri ve/veya dizileri yukarıdaki şekilde hayata getirirsek, 'garbage-value' veya 'indetermined value' ile hayata gelirler. >>> 'statik' ömürlü değişkenler ise önce 'zero-initialize' edilirler. >>>> 'zero-initialize' : Primitiv türden değişkenler hayata 'sıfır' değeriyle, boolean türden değişkenler 'false' değeriyle ve 'pointer' türden değişkenler ise 'nullptr' ile hayata gelir. Sınıf türünden nesneler ise nesnenin bütün 'data member' ları yukarıdaki şekilde 'zero-initialize' edilirler. * Örnek 1, #include class Myclass { public: void print() { std::cout << "m_b : " << m_b << "\n"; std::cout << "m_i : " << m_i << "\n"; std::cout << "m_f : " << m_f << "\n"; } private: bool m_b; int m_i; float m_f; }; Myclass mb; // Statik ömürlü bir değişken olduğu için 'default Ctor' çağrıldı ve bütün elemanlar 'zero-initialize' edili. int main() { Myclass ma; // Otomatik ömürlü bir değişken olduğu için 'default Ctor' çağrıldı ve bütün elemanlar 'garbage-value' // ile hayata geldi. ma.print(); /* # OUTPUT # m_b : 173 m_i : -1167531328 m_f : 4.59163e-41 */ mb.print(); /* # OUTPUT # m_b : 0 m_i : 0 m_f : 0 */ } >>> Bir sınıf türünden otomatik ömürlü nesneler için ise 'default Ctor.' çağrılır. Eğer 'default Ctor' yok ise SENTAKS HATASI alırız. * Örnek 1, #include class Myclass { public: Myclass(int b, int i, int f) { m_b = b; m_i = i; m_f = f; } void print() { std::cout << "m_b : " << m_b << "\n"; std::cout << "m_i : " << m_i << "\n"; std::cout << "m_f : " << m_f << "\n"; } private: bool m_b; int m_i; float m_f; }; int main() { Myclass ma; // error: no matching function for call to ‘Myclass::Myclass()’ ma.print(); } >> 'value-initialize' : "int x{};", "Myclass mx{};", "int a[]{};" şeklinde hayata getirme biçimidir. Küme parantezinin içinin boş olması gerekmektedir. Dolayısıyla değişkenler önce 'zero-initialize' edilirler. * Örnek 1, // some code here... struct Myclass{ int mx, my; }; Myclass gx; // Global bir değişken olduğu için bütün elemanları önce 'zero-initialize' edildi. Ondan sonra 'default Ctor' // çağrıldı ama hiç bir şey yapmadı. int main() { Myclass gy; // 'gy' nesnesi 'default-initialize' edildi. 'default Ctor' çağrıldı ama hiç bir şey yapmadığı için 'mx' ve 'my' // isimli 'data members' lar ÇÖP DEĞER tutmaktalar. Myclass gz{}; // 'gz' nesnesinin bütün elemanları önce 'zero-initialize' edildi. Ondan sonra 'default Ctor' çağrıldı ama hiç // bir şey yapmadı. } >> 'direct-initialize' : "Myclass mx(10);" şeklindeki hayata getiriş biçimidir. Duruma göre uygun 'parametreli Ctor' çağrılacaktır. >> 'copy-initialization' : "Myclass mx = 200;" şeklindeki hayata getiriş biçimidir. Tehlikelidir. Uygun şartlar altında parantezin sağ tarafındaki 'primitive' türden değişkenleri sınıf türüne dönüştürebilir. >> 'direct-list-initialization' : "Myclass mx{500};" şeklindeki hayata getiriş biçimidir. 'brace initialization' da denir. 'Narrowing Conversion' sentaks hatasına neden olur. Yukarıdaki her iki yöntemde ise bu durum LEGAL ama veri kaybına neden olur. >> Yukarıdaki üç yöntem için örnek, * Örnek 1, // some code here... struct Myclass{ Myclass(int x, int y) { mx = x; my = y; } int mx, my; }; int main() { /* # OUTPUT # 12_24 36_48 60_72 */ Myclass m1(12, 24); // direct-initialize Myclass m2{36, 48}; // brace-initialize Myclass m3 = {60, 72}; // copy-initialize std::cout << m1.mx << "_" << m1.my << std::endl; std::cout << m2.mx << "_" << m2.my << std::endl; std::cout << m3.mx << "_" << m3.my << std::endl; } > ODR (One-Definition-Rule) ve 'inline' Fonksiyonlar: >> Cpp dilinde değişkenlerin, fonksiyonların ve sınıfların bildirimleri birden fazla kez yapılabilir fakat tanımlarının birden fazla kez yapılması ya SENTAKS HATASI ya da 'tanımsız davranış'. * Örnek 1, // AYNI KAYNAK DOSYADA int a; // This's a DEFINITION int a; // 'redefinition'. SENTAKS HATASI. extern int b; // This's a DECLERATION extern int b; // Legal extern int b; // Legal int b; // This's a DEFINITION int b; // 'redefinition'. SENTAKS HATASI. class A; // This's a Forward-DECLERATION class A; // Legal class A{}; // This's a DEFINITION class A{}; // 'redefinition'. SENTAKS HATASI. void func(int); // This's a DECLERATION void func(int); // Legal void func(int); // Legal void func(int) // This's a DEFINITION { } void func(int) // 'redefinition'. SENTAKS HATASI. { } // FARKLI KAYNAK DOSYADA // Inside main.cpp class A{ int a,b,c; }; void func(int) // This's a DEFINITION { } int main() { } // Inside neco.cpp class A{ int ma, mb, mc; }; void func(int) // This's a DEFINITION { } // BU DURUMDA HEM FONKSİYON TANIMLARKEN HEM DE SINIFLARI TANIMLARKEN 'ODR' İHLAL EDİLMİŞ OLDU VE // 'Tanımsız Davranış'. DERLEME ZAMANINDA HATA ALMAYIZ AMA BİR İHTİMAL 'link' AŞAMASINDA 'linker' HATA // VEREBİLİR. Eğer yukarıdaki 'func()' isimli fonksiyonları 'static' anahtar sözcüğü ile niteleseydik, ilgili // fonksiyonu 'iç bağlantıya' alacağımız için, ODR ihlal edilmemiş olur. Eğer yukarıdaki 'A' türünden // sınıfların tanımlamalarını 'token-by-token' birbirinin AYNISI yapsaydık, ODR ihlal edilmemiş olur. // Şablonlarda(templates) da 'token-by-token' birbirinin AYNISI ise ODR ihlal edilmemiş olur. Başlık dosyası // içerisinde tanımlayacağımız değişkenleri ve fonksiyonları 'inline' anahtar sözcüğü ile betimlersek, ODR // ihlal edilmemiş olur. /* KISACA, - BAŞLIK DOSYASI IÇERISINDE YAPACAĞıMıZ DEĞIŞKEN VE FONKSIYON TANIMLAMALARINI 'INLINE' ANAHTAR SÖZCÜĞÜ ILE NITELEMEMIZ GEREKIYOR KI ODR IHLAL EDILMESIN. 'USER-DEFINED' TÜRLER EĞER 'TOKEN-BY-TOKEN' AYNı ISE ZATEN ODR IHLAL ETMIYOR. - FARKLı KAYNAK DOSYALARDAKI AYNı ISIMDEKI FONKSIYONLARDAN BAZILARINI 'IÇ BAĞLANTıYA' AÇARAK ODR IHLAL EDILMESIN. */ >> 'inline' Fonksiyonlar : Fonksiyon tanımlarını 'inline' anahtar sözcüğünün kullanılması ile elde edilir. >>> Yukarıdaki ODR ihlalini engellemek için kullanılır. >>> Derleyici, bir fonksiyon çağrısının yapıldığı yerde fonksiyonun tanımını da görürse, o çağrı yerine fonksiyonun derlenmiş halini yazıyor. 'linker' a işi havale etmiyor.Fakat bu durum %100 geçerli değil. Fonksiyonun tanımını gördüğünden dolayı, bir avantaj sağlayacağını düşündüğü noktada, yer değişikliği yapabilir. Ama fonksiyonun kodları çok karışık ise yer değiştirme işlemi yapmayadabilir. Yani bizler bir nevi derleyiciden 'rica ediyoruz'. Diğer yandan bu değişikliği 'inline' anahtar sözcüğü olmadan da derleyici yapabilir. >>> Bir fonksiyonun tanımını, sınıfın tanımı içerisinde yaparsak, bu fonksiyon direkt 'inline' olur. İlgili 'inline' anahtar sözcüğünü kullanmamız yada kullanmamamız durumu değiştirmez. * Örnek 1, // APPROACH I // Inside neco.hpp file class Myclass{ public: void foo(int) // Artık bu 'foo()' fonksiyonu bir inline. { //... } }; // APPROACH II // Inside neco.hpp file class Myclass{ public: /*inline*/ void foo(int); // 'inline' anahtar sözcüğünü ister bildirime ister tanıma yazın. }; /*inline*/ void Myclass::foo(int) { //... } >>> Derleyici tarafından 'implicitly-declared' olan 'special member functions' birer 'inline' fonksiyonlardır.