* Örnek 1, Kolay seviye zorluk soruları: //.. void f(int& a, const int& b) { std::cout << b; // 'b' demek 'x' demektir. a = 1; // 'a' demek de 'x' demektir. std::cout << b; } int main() { /* # OUTPUT # 01 */ int x = 0; f(x, x); } * Örnek 2, //.. int main() { /* # OUTPUT # 0 */ // 'static' ömürlü değişkenler 'default init.' edilmeleri durumunda ilk önce 'zero-init.' edilirler. static int a; std::cout << a: } * Örnek 3, //.. class A { int foo = 0; public: int& getFoo() { return foo; } void printFoo() const { std::cout << foo; } }; int main() { A a; auto bar = a.getFoo(); // '&' deklaratörü kullanılmadığından, referanslık düşmektedir. ++bar; a.printFoo(); // OUTPUT => 0 } * Örnek 4, //.. class A { public: A() { std::cout << 'a'; } // ii. Dolayısıyla bu fonksiyon çağrılacak. ~A() { std::cout << 'A'; } // v. Son olarak bu nesnenin hayatı bitecek. }; class B { public: B() { std::cout << 'b'; } // iii. Sonrasında bu nesne hayata gelecek. ~B() { std::cout << 'B'; } // iv. En son bu nesne hayata geldiği için ilk önce bu nesnenin hayatı bitecek. A a; // i. İlk önce bu nesne hayata gelecek. }; int main() { B b; // OUTPUT => abBA } * Örnek 5, //.. void f(int) { std::cout << 1; } void f(unsigned) { std::cout << 2; } int main() { f(-2.5); // 'double' to 'int' : 'standart conversion' // 'double' to 'unsigned' : 'standart conversion' // Syntax Error : error: call of overloaded ‘f(double)’ is ambiguous } * Örnek 6, //.. int main() { int a = 10; int b = 20; int x; x = a, b; // '=' operatörünün önceliği ',' operatörünün önceliğinden yüksek olduğu için, std::cout << x; // OUTPUT => 10 std::cout << std::endl; x = (a,b); std::cout << x; // OUTPUT => 20 } * Örnek 7, //.. int main() { std::cout << sizeof(""); // Argüman olan ifadenin türü 'const char[1]'. Fakat değeri hesaplanmayacağı için 'array-decay' // gerçekleşmeyecektir. // OUTPUT => 1 } * Örnek 8, //.. class A { public: virtual void f() { std::cout << "A"; } }; class B : public A { public: void f() { std::cout << "B"; } }; void g(A a) { a.f(); } // 'g' fonksiyonunun parametresi 'pointer' DEĞİLDİR. void gg(A& a) { a.f(); } int main() { B b; g(b); // OUTPUT => A // İsim arama kuralları gereği, 'g()' içindeki 'f()' fonksiyonu, 'A' sınıfında aranmıştır. // 'g()' fonksiyonu 'pointer'/'reference' ile argüman almadığı için 'virtual-dispatch' söz konusu da değildir. // 'object-slicing' devreye girmiştir. 'b' içerisindeki 'a', fonksiyona argüman olmuştur. gg(b); // OUTPUT => B // 'pointer' kullandığımız için 'virtual-dispatch' devreye girmiştir. } * Örnek 9, //.. void f(char* &&) { std::cout << 1; } // 'R-value reference' to 'char*' void f(char* &) { std::cout << 2; } // 'L-value reference' to 'char*' int main() { char c = 'a'; f(&c); // 'PR-value' expression. OUTPUT => 1 } * Örnek 10, //.. using namespace std; bool default_constructed = false; bool constructed = false; bool assigned = false; class C { public: C() { default_constructed = true; } C(int) { constructed = true; } C& operator=(const C&) { assigned = true; return *this; } }; int main() { map m; // i. Boş bir 'std::map' nesnesi hayata gelmekte. m[7] = C(1); // ii. Dolayısıyla bir 'std::pair<>' hayata getirilmekte ki bunun 'first' isimli değişkeni '7' ile 'second' // isimli değişkeni de 'C' nesnesi. Fakat 'default init.' edilmiştir. // iii. Sonrasında geçici 'C' nesnesi hayata gelmekte. // iv. Son olarak da geçici bu nesne 'default init.' edilen 'C' nesnesine atanmıştır. cout << default_constructed << constructed << assigned; // 111 }; * Örnek 11, //.. struct A { A() { std::cout << "A"; } // v. Dolayısıyla bu fonksiyon çağrıldı. }; struct B { B() { std::cout << "B"; } // iii. Bundan dolayı da fu fonksiyon çağrıldı. }; class C { public: C() : a(), b() {} private: B b; // ii. Bildirimdeki sıra ile hayata ilk bu geldi. A a; // iv. Sonrasında sıra bunun hayata gelmesinde geldi. }; int main() { C(); // i. Geçici 'C' türünden bir nesne oluşturuldu. // OUTPUT => BA } * Örnek 12, //.. struct GeneralException{ virtual void print() { std::cout << "G"; } }; struct SpecialException : public GeneralException { void print() override { std::cout << "S"; } }; void f() { throw SpecialException(); } int main() { try { f(); } catch (GeneralException e) { e.print(); // 'reference' semantiği kullanılmadığı için 'virtual dispatch' devreye girmeyecektir. 'object-slicing' // meydana gelmiştir. // OUTPUT => G } } * Örnek 13, //.. int main() { int a = 0; decltype((a)) b = a; // 'b' demek 'a' demek. Demek çünkü '(a)' bir 'L-Value Expression'. // int& b = a; b++; std::cout << a << b; // OUTPUT => 11 // decltype(isim) => 'isim' hangi tür ise 'decltype(isim)' de o tür. Bir nevi 'auto' şeklindeki // tür çıkarımı gibi. // decltype(ifade) => 'ifade' eğer 'L-Value Expression' ise 'decltype(ifade)' o türe referans. // eğer 'PR-Value Expression' ise 'decltype(ifade)' o türün kendisi. // eğer 'X-Value Expression' ise 'decltype(ifade)' o türün sağ taraf referansı. } * Örnek 14, //.. class A { public: void f() { std::cout << "A"; } }; class B : public A { public: void f() { std::cout << "B"; } }; void g(A& a) { a.f(); } int main() { B b; g(b); // OUTPUT => A // Dolayısıyla isim arama kuralları gereği, 'g()' içindeki 'f' fonksiyon ismi, 'A' sınıfında aranmıştır. // Taban sınıfımız içerisindeki 'f()' fonksiyonu, 'virtual' olmadığı için, 'virtual-dispatch' mekanizmasından // söz edilemez. // 'object-slicing' devreye girmiştir. 'b' içerisindeki 'a', fonksiyona argüman olmuştur. } * Örnek 15, //.. int f(int& a, int& b) { a = 3; // i. Buradaki 'a', 'main' içerisindeki 'a' demektir. 'main' içerisindeki 'a' artık '3' değerinde. b = 4; // ii. Buradaki 'b', 'main' içerisindeki 'a' demektir. 'main' içerisindeki 'a' artık '4' değerinde. return a + b; // iii. '8' değeri geri döndürülecektir. } int main() { int a = 1; int b = 2; int c = f(a, a); // iv. 'c' artık '8' değerindedir. std::cout << a << b << c; // OUTPUT => 428 } * Örnek 16, //.. void f(int& a, const int& b) { std::cout << b; // i. 'b' demek 'x' demektir. a = 1; // ii. 'a' demek de 'x' demektir. std::cout << b; // iii. 'a' vesilesiyle 'x' in değeri değişmiştir. } int main() { int x = 0; f(x, x); // OUTPUT => 01 } * Örnek 17, //.. class A { public: // iii. Fakat ilgili 'f()' fonksiyonumuz 'virtual' olduğundan ve 'g()' fonksiyonu da referans/gösterici // yoluyla argüman aldığından 'virtual-dispatch' devreye girecek. virtual void f() { std::cout << "A"; } }; class B : public A { private: void f() { std::cout << "B"; } // iv. Günün sonunda da bu fonksiyon çağrılacaktır. }; void g(A& a) { a.f(); } // ii. Dolayısıyla 'f()' için isim arama 'A' sınıfı içerisinde yapılacak ve bulunacak. int main() { B b; g(b); // i. İlgili 'g()' fonksiyonumuz referans yoluyla argüman almaktadır. // # SIRALAMA # // 1. 'name-lookup' => Derleme zamanı ile ilgili. // 2. 'context-control' => Derleme zamanı ile ilgili. // 3. 'access-control' => Derleme zamanı ile ilgili. // OUTPUT => B // NOT: İsim arama derleme aşamasıyla ilgili olup, 'virtual-dispatch' çalışma zamanıyla ilgilidir. Dolayısıyla // isim arama sırasında ilgili 'f()' fonksiyonumuz 'A' sınıfında arandığı ve bulunduğu için sonlanmıştır. Artık // bu aşamadan sonra isim arama ile ilgili kurallar geride kalmıştır. Bu yaklaşım ile bir sınıfın 'private' // bölümündeki fonksiyonları çağırabildiğimizi görmüş olduk. // NOT-2: Taban sınıfın sanal veya sap-sanal fonksiyonları, ilgili sınıfın 'private', 'protected' ve 'public' // kısımlarında olabilir. Bu, iş bu fonksiyonları 'override' EDEMEYECEĞİM anlamına gelmemektedir. } * Örnek 18, //.. class A { public: A() { std::cout << "a"; } ~A() { std::cout << "A"; } }; class B { public: B() { std::cout << "b"; } ~B() { std::cout << "B"; } }; class C { public: C() { std::cout << "c"; } ~C() { std::cout << "C"; } }; A a; // i. İlk önce bu nesne hayata gelecektir. int main() { C c; // ii. Sonrasında bu nesne hayata gelecektir. B b; // iii. Devamında da bu nesne hayata gelecektir. // iv. En son 'b' nesnesi hayata geldiğinden, ilk onun hayatı bitecektir. // v. Ondan sonra 'c' nesnesinin hayatı bitecektir. // vi. En son olarak da 'a' nesnesinin hayatı bitecektir. // OUTPUT => acbBCA } * Örnek 19, //.. struct C { C() : i(1) {} int i; }; struct D { D() : i(2) {} int i; }; int main() { const std::variant v; // i. 'default init.' edildiğinden şu an 'C' sınıfından bir veri tutmaktadır. 'i' değişkeninin değeri '1'. std::visit([](const auto& value) { std::cout << value.i; }, v); // OUTPUT => 1 } * Örnek 20, //.. int main() { int i = 42; int j = 1; std::cout << i / --j; // 'Tanımsız Davranış'. Çünkü ilk olarak 'j' değişkeninin değeri bir azaltılacak. Bu sefer de sıfıra bölme ile // karşılaşacağız. İşaretli sayılarda sıfıra bölme 'Tanımsız Davranış' } * Örnek 21, //.. int j = 1; int main() { // i. Virgüller ile ayrılan bildirimlerde gösterici veya referans niteleyicisi sadece ilk değişken için // geçerlidir. int& i = j, j; // int& i = j; // int j; j=2; // ii. Artık buradaki 'j', 'main' içerisindeki 'j'. Global isim alanındaki 'j' maskelenmiştir. std::cout << i << j; // OUTPUT => 12 } * Örnek 22, Orta seviye zorluk soruları: //.. namespace x { class C {}; void f(const C& i) { std::cout << "1"; } } namespace y { void f(const x::C& i) { std::cout << "2"; } } int main() { f(x::C()); // OUTPUT => 1 // Fonksiyonun argümanı 'x' isim alanında bildirildiğinden, onu nitelememiz gerekiyor ki 'C' sınıf türünden // geçici bir nesne oluşturabilelim. 'ADL' mekanizmasından dolayı da fonksiyonun argümanlarının bulunduğu isim // alanında, fonksiyonun ismi aranmaktadır. Dolayısıyla 'x' isim alanında 'f' ismi de aranacaktır. İş bu sebepten // dolayı ekrana '1' yazılmıştır. } * Örnek 23, //.. namespace x { class C {}; void f(const C& i) { std::cout << "1"; } } namespace { void f(const x::C& i) { std::cout << "2"; } } int main() { f(x::C()); // OUTPUT => error: call of overloaded ‘f(x::C)’ is ambiguous // İsimsiz isim alanı içerisinde tanımlanan 'f' fonksiyonu aslında C dilindeki 'static' global fonksiyonlardır. // Yani 'internal-linkage' durumundakiler. 'x' isim alanı içerisinde tanımlanan 'f' fonksiyonu ise yine aynı isim // alanında tanımlanan 'C' sınıf türünden bir değişken almaktadır. Bu durumda hem 'ADL' mekanizması vesilesiyle // 'x' isim alanında hem de global isim alanında 'f' ismi bulunacak. Başka bir seçim kriter olmadığı için, bundan // dolayı da 'ambiguous' tip sentaks hatası alacağız. Burada hem normal olarak hem de ADL ile birlikte isim // aranmaktadır. Birbirlerine karşı öncelikleri yoktur, arama için. } * Örnek 24, //.. int i; // i. 'i' değişkeninin değeri şu an '0'. void f(int x) { std::cout << x << i; // iv. Burada 'x' değişkeni '3', 'i' ise '4' değerine sahiptir. } int main() { i = 3; // ii. 'i' değişkeninin değeri artık '3' oldu. f(i++); // iii. Fonksiyona argüman olarak '3' değeri gönderildi. Fonksiyon çağrısı olduğundan yan etki gerçekleşecek ve // 'i' değişkeni '4' değerini alacak. // OUTPUT => 34 } * Örnek 25, //.. struct S { int one; int two; int three; }; int main() { S s{ 1,2 }; std::cout << s.one; std::cout << s.two; std::cout << s.three; // OUTPUT => 120 // İlgili 'S' türümüz 'aggregate' tür olduğundan; // 'one' isimli değişkeni '1' değeri ile, // 'two' isimli değişken '2' değeri ile, // 'three' ise '0' değeri ile hayata gelmiştir. // Aggregate: An aggregate is an array or a class (clause 9) with // no user-declared constructors (12.1), // no private or protected non-static data members (clause 11), // no base classes (clause 10), and no virtual functions (10.3). } * Örnek 26, //.. int main() { std::cout << std::boolalpha << std::is_signed::value; // OUTPUT => true // 'unsigned char', 'signed char' ve 'char' türleri birbirinden farklı türler olup; // 'unsigned char' türü işaretsiz, // 'signed char' türü işaretli, // 'char' türününü işaret bilgisi ise 'implementation defined' şeklindedir. Yani bir nevi derleyiciye bağlıdır. } * Örnek 27, //.. struct X { X() { std::cout << "1"; } X(X&) { std::cout << "2"; } X(const X&) { std::cout << "3"; } X(X&&) { std::cout << "4"; } ~X() { std::cout << "5"; } }; struct Y { mutable X x; Y() = default; Y(const Y&) = default; }; int main() { Y yOne; Y yTwo = std::move(yOne); // OUTPU => 1255 // i. 'yOne' için 'Ctor.' fonksiyonu çağrılacaktır. Bu da öncesinde veri elemanı olan 'x' değişkenine ait // 'Ctor.' fonksiyonunu çağıracaktır. // Bu işlem sonucunda ekrana '1' yazılacaktır. // ii. Daha sonra 'std::move()' çağrısı ile 'yOne' değişkeninin türü 'R-value' türüne dönüştürülecektir. // iii. Dolayısıyla 'yTwo' için 'Move Ctor.' fonksiyonu çağrılacaktır fakat OLMADIĞI İÇİN ONUN YERİNE sınıfın // 'Copy Ctor.' fonksiyonu çağrılacaktır. Fakat ilgili 'Copy Ctor.' fonksiyonunu derleyicinin yazdığını da // unutmayalım. Derleyici bu çağrıdan hareketle, 'X' sınıfı için de 'Copy Ctor.' fonksiyonunu çağıracaktır. İki // adet 'Copy Ctor.' adayı olduğu görülmektedir. İlgili 'x' isimli veri elemanımız 'mutable' olarak nitelendiği // için derleyici üstteki versiyonu seçecektir ve bu seçim sonucunda ekrana '2' yazılacaktır. 'mutable' olarak // NİTELEMESEYDİK EĞER aşağıdaki versiyonu seçecekti. // iv. En son hayata gelen 'yTwo' içerisindeki 'x' olduğu için ilk onun hayatı sona ereceğinden, ekrana '5' // yazılacaktır. // v. Sonrasında da 'yOne' içerisindeki 'x' hayata veda edeceğinden, ekrana yine '5' yazılacaktır. } * Örnek 28, //.. struct X { X() { std::cout << "1"; } X(const X&) { std::cout << "2"; } X(X&&) { std::cout << "3"; } }; struct Y { X m_x; Y() { std::cout << "4"; } Y(const Y& x) : m_x{x.m_x} { std::cout << "5"; } Y(Y&& x) : m_x{x.m_x} { std::cout << "6"; } }; int main() { // i. İlk önce 'Y' içerisindeki 'm_x' hayata geleceğinden ekrana önce '1', sonrasında da '4' yazılacaktır. Y yOne; Y yTwo = std::move(yOne); // ii. 'yOne' sağ taraf haline dönüştürülecek ve 'yTwo' için 'Move Ctor.' çağrılacaktır. Bu da ekrana önce '2', // sonrasında da '6' yazılmasına neden olacaktır. Çünkü 'Y' sınıfının 'Move Ctor.' fonksiyonu bloğunda 'X' // sınıfının 'Move Ctor.' fonksiyonuna çağrı olmadığından, 'Copy Ctor.' fonksiyonu çağrılacaktır. // OUTPUT => 1426 } * Örnek 29, //.. class A { public: A() { cout << "a"; } ~A() { cout << "A"; } }; int i = 1; int main() { label: A a; if (i--) goto label; // OUTPUT => aAaA // i. Programın akışı ilk olarak 'a' değişkeninin tanımına geldiğinde sınıf türünden değişkenimiz hayata gelecek. // Bundan sebep ekrana 'a' yazılacak. // ii Sonrasında programın akışı 'if' bloğuna girdiğinde, oradan da 'goto' üzerinden tekrardan 'a' değişkeninin // tanımın geldiğinde, az evvel hayata getirilen değişkenin hayatı bitecek. Ömrü bitmiş muamalesi görecek. Bundan // sebep ekrana 'A' yazılacak. // iii. Fakat programın akışı yine bir değişken bildirimine geldiğinden dolayı tekrardan bir 'a' değişkeni hayata // gelecek. Bundan dolayı da ekrana 'a' yazacak. // iv. Son olarak programın akışı 'if' bloğuna girmeyecek çünkü yan etkiden dolayı ve değişkenlerimizin hayatı // bitecek. Bu da ekrana 'A' yazılmasına neden olacak. } * Örnek 30, //.. void takes_pointer(int* pointer) { if (typeid(pointer) == typeid(int[])) std::cout << 'a'; if (typeid(pointer) == typeid(int*)) std::cout << 'p'; // ii. Ekrana bu yazı yazılacaktır. } void takes_array(int array[]) { if (typeid(array) == typeid(int[])) std::cout << 'a'; if (typeid(array) == typeid(int*)) std::cout << 'p'; // iii. Ekrana bu yazı yazdırılacaktır. } int main() { int* pointer = nullptr; int array[1]; takes_pointer(array); // i.'array-decay' gerçekleşecektir. 'int[1]' => 'int*' takes_array(pointer); std::cout << (typeid(int*) == typeid(int[])); // iv. Ekrana '0' yazdırılacaktır. // OUTPUT => pp0 } * Örnek 31, //.. int main() { std::cout << std::is_pointer_v; // i. 'nullptr', 'nullptr_t' türünden bir değişken ismi. // ii. 'decltype()' içerisinde bir isim kullanıldığından, çıkan tür bilgisi o türün kendisi. Yani 'nullptr_t'. // 'nullptr_t' türü ise bir 'class-type' fakat bir gösteriyice dönüşebilmektedir. // OUTPUT => 0 } * Örnek 32, //.. struct A { A() { foo(); } virtual ~A() { foo(); } virtual void foo() { std::cout << "1"; } void bar() { foo(); } }; struct B : public A { virtual void foo() { std::cout << "2"; } }; int main() { B b; b.bar(); // i. İlk önce 'B' sınıfının içerisindeki 'A' sınıfı hayata gelecektir. Bu da ekrana '1' yazdırtacaktır. // ii. Daha sonra taban sınıf içerisindeki '.bar()' isimli üye fonksiyona çağrı yapılacaktır ki bu da ekrana '2' // yazdırtacaktır. Çünkü 'virtual-dispatch' mekanizması DEVREYE GİRECEKTİR. // iii. Son olarak da hayatı biten 'B' sınıfı için 'Dtor.' fonksiyonu çağrılacaktır ki bu da ekrana '1' // yazdırtacaktır. // OUTPUT => 121 } * Örnek 32, //.. class Base{ public: virtual void myBase() { std::cout << "1" << std::endl; } void myBaseTwo() { std::cout << "2" << std::endl; } }; class Der : public Base{ public: virtual void myBase() override { std::cout << "3" << std::endl; } void myDer() { std::cout << "4" << std::endl; } }; void foo(Base other) { other.myBase(); } void foo(Base* other) { other->myBase(); } int main() { std::cout << "--" << std::endl; Base one; one.myBase(); // OUTPUT => 1 one.myBaseTwo(); // OUTPUT => 2 // one.myDer(); // error: ‘class Base’ has no member named ‘myDer’ std::cout << "--" << std::endl; Der two; two.myBase(); // OUTPUT => 3 two.myBaseTwo(); // OUTPUT => 2 two.myDer(); // OUTPUT => 4 std::cout << "--" << std::endl; foo(one); // OUTPUT => 1 std::cout << "--" << std::endl; foo(two); // OUTPUT => 1 std::cout << "--" << std::endl; foo(&one); // OUTPUT => 1 std::cout << "--" << std::endl; foo(&two); // OUTPUT => 3 } * Örnek 33, //.. struct A { virtual void foo(int a = 1) { std::cout << "A" << a; } }; struct B : A { virtual void foo(int a = 2) { std::cout << "B" << a; } }; int main() { A* b = new B; b->foo(); // OUTPUT => B1 // i. 'foo()' ismi derleme aşamasında 'A' sınıfı içerisinde aranır ve varsayılan argüman olarak 'a' değişkeninin // '1' değeri alacağını görür. // ii. Çalışma zamanında 'virtual-dispatch' mekanizması devreye gireceğinden, fonksiyon çağrısı 'B' sınıfındakine // bağlanır. Fakat varsayılan argüman olarak '1' değerini alacağını daha önce öğrendiğinden 'a' yerine '1' gelir. } * Örnek 34, //.. int main() { if (std::is_signed::value) std::cout << std::is_same::value; else std::cout << std::is_same::value; // 'char' türünün işaret durumu derleyiciye bağlıdır. Dolayısıyla programın akışı // 'if' bloğuna da girebilir ama 'else' bloğuna da. Fakat her iki blok içerisinde de // 'std::is_same<>' sınaması yapılmış. 'char', 'unsigned char' ve 'signed char' türleri // birbirinden farklı tür olduklarından, her halükarda '0' değeri döndürülecektir. } * Örnek 36, // int main() { std::cout << std::is_same_v< void(int), void(const int)>; // C ve Cpp dilinde gösterici olmayan türler için türün kendisine ait 'const' nitelenmesi, imzada bir farklılık // oluşturmamaktadır. std::cout << std::is_same_v< void(int*), void(const int*)>; // Burada gösterici kullanıldığından, imzalar da farklı olacaktır. // OUTPUT => 10 } * Örnek 37, // int main(int argc, char* argv[]) { /* # OUTPUT # 132765 &a[0] : 0x7ffd3ce545d0 &a[1] : 0x7ffd3ce545d4 &a[2] : 0x7ffd3ce545d8 &a[3] : 0x7ffd3ce545dc &a[4] : 0x7ffd3ce545e0 &a[5] : 0x7ffd3ce545e4 */ std::cout << (argv[argc] == nullptr); // Standartlara göre, 'argv' isimli dizinin 'argc' numaralı öğesi 'nullptr' olmak zorunda. Bu kural sadece // komut satırı argümanlarında geçerlidir. int a[5] = { 0 }; std::cout << a[5] << std::endl; // Bu tip 'C-array' ler için, ilgili indeksin sadece adresini alabiliriz. Geri kalan işlemler 'Tanımsız Davranış'. std::cout << "&a[0] : " << &a[0] << std::endl; std::cout << "&a[1] : " << &a[1] << std::endl; std::cout << "&a[2] : " << &a[2] << std::endl; std::cout << "&a[3] : " << &a[3] << std::endl; std::cout << "&a[4] : " << &a[4] << std::endl; std::cout << "&a[5] : " << &a[5] << std::endl; } * Örnek 38, // int main() { int x = 10; int y = 10; // Standartlara göre 'std::max()' ve 'std::min()' fonksiyonlarına geçilen argümanlar eşit ise birinci // argümanı döndürmelidir. const int& max = std::max(x, y); // 'max' demek 'x' demek. const int& min = std::min(x, y); // 'min' demek 'x' demek. x = 11; y = 9; std::cout << max << min; // OUTPUT => 1111 } * Örnek 39, // class C { public: C(int i) : i(i) { std::cout << i; } ~C() { std::cout << i + 5; } private: int i; }; int main() { const C& c = C(1); C(2); C(3); // OUTPUT => 127386 // ^^^^^^ // |||||'C(1)' nesnesinin hayatı bittiğinde. // ||||'C(3)' nesnesinin hayatı bittiğinde. // |||'C(3)' nesnesi hayata geldiğinde. // ||'C(2)' nesnesinin hayatı bittiğinde. // |'C(2)' nesnesi hayata geldiğinde. // 'C(1)' nesnesi hayata geldiğinde. 'life-extension' gerçekleşmiştir. } * Örnek 40, // int main() { std::variant v; // 'default-init.' edildiğinden, 'int' türden tutacaktır. std::cout << v.index(); // OUTPUT => 0 } * Örnek 41, //.. int main() { std::cout << 1["ABC"]; // std::cout << "ABC"[1]; // OUTPUT => B // Pointer arithmatic. } * Örnek 42, //.. int main() { std::cout << 2["elma"] - 1["elma"] << std::endl; // std::cout << 'm' - 'l' << std::endl; // ASCII karakter tablosundaki karakterlere karşılık gelen rakamlar çıkartılmıştır. // OUTPUT => 1 } * Örnek 43, //.. void f( int a = []() { static int b = 1; return b++; }() ) { std::cout << a; } int main() { f(); // i. Varsayılan argüman olan 'lambda-expression' a göre derleyici bir sınıf kodu yazacaktır. Bu sınıfın // '.operator()()' fonksiyon bloğunda ise 'b' değişkeni '1' değeri ile hayata gelecektir. Ekrana da '1' rakamını // yazdıracak, sonrasında da değeri '2' olacaktır. f(); // ii. Yine aynı 'lambda-expression' kullanılacaktır. Bu sefer 'b' değişkeninin değeri '2' olduğundan ekrana '2' // yazdırılacaktır. Sonrasında da değeri '3'. // OUTPUT => 12 } * Örnek 44, //.. int main() { char* a = const_cast("Hello"); a[4] = '\0'; std::cout << a; // 'const' nesneleri DEĞİŞTİRMEYE ÇALIŞMAK HER ZAMAN 'Tanımsız Davranış' OLUR. } * Örnek 45, //.. int foo() { return 10; } struct foobar { static int x; static int foo() { return 11; } }; int foobar::x = foo(); // i. 'x' değişkeni 'static' olması hasebiyle, 'foo()' fonksiyonu da 'class-scope' içinde aranacaktır. Bu yüzden // 'x' değişkeninin değeri '11'. int main() { std::cout << foobar::x; } * Örnek 46, //.. struct X { X() { std::cout << "a"; } X(const X& x) { std::cout << "b"; } const X& operator=(const X& x) { std::cout << "c"; return *this; } }; int main() { X x; // OUTPUT => a X y(x); // 'direct-init.' // OUTPUT => b X z = y; // 'copy-init.' // OUTPUT => b z = x; // OUTPUT => c } * Örnek 47, //.. size_t get_size_1(int* arr) { return sizeof arr; } size_t get_size_2(int arr[]) { return sizeof arr; } size_t get_size_3(int(&arr)[10]) { return sizeof arr; } int main() { int array[10]; // 'array-decay' gerçekleşecektir ve 'array' artık 'int*' türündendir. İkisinin büyüklüğü farklıdır. std::cout << (sizeof(array) == get_size_1(array)); // 'array-decay' gerçekleşecektir ve 'array' artık 'int*' türündendir. İkisinin büyüklüğü farklıdır. std::cout << (sizeof(array) == get_size_2(array)); std::cout << (sizeof(array) == get_size_3(array)); // 'array-decay' GERÇEKLEŞMEYECEKTİR. Fonksiyon parametresi 'arr', 10 boyutlu bir 'int' diziye referanstır ki // bu da aslında bizim 'array' isimli dizimiz. 'arr' demek 'array' demektir. // OUTPUT => 001 } * Örnek 48, //.. struct A { A(int i) : m_i(i) {} operator bool() const { return m_i > 0; } int m_i; }; int main() { A a1(1), a2(2); std::cout << a1 + a2 << (a1 == a2); // Sınıfımızın '.operator+()' ve '.operator==()' fonksiyonları olmadığı için, // yukarıdaki '+' ve '==' işlemleri için sınıfımızın '.operator bool()' fonksiyonu // çağrılacaktır. Çünkü '.operator bool()' fonksiyonu 'explicit' değildir. // Dolayısıyla; // i. '+' işlemi sırasında her iki nesne için '.operator bool()' fonksiyonu 'true' değerini döndürecektir. Bu da // 'int' türüne 'cast' edilecektir. Dolayısıyla ilk olarak ekrana '2' yazacaktır. // ii. Devamında ise '==' işlemi sırasında iki 'bool' tür birbiri ile karşılaştırılacak ve 'true' değer elde // edilecektir. Bu da 'int' türüne 'cast' edilecektir. Bundan sebeptir ki ekrana '1' yazacaktır. // OUTPUT => 21 // Buradaki kilit nokta '.operator bool()' fonksiyonunun 'explicit' olmamasıdır. } * Örnek 49, //.. template void f(T) { static int i = 0; std::cout << ++i; } int main() { f(1); // 'int' türü için şablon açılacaktır. Dolayısıyla 'f' içerisindeki 'i' değişkeninin değeri '0' fakat ekrana // '1' yazdıracaktır. Çünkü artık değeri '1'. f(1.0); // 'double' türü için şablon açılacaktır. Dolayısıyla 'f' içerisindeki 'i' değişkeninin değeri '0' olacak ve // ekrana '1' yazdıracaktır. f(1); // 'int' türü için ŞABLON AÇILMAYACAKTIR. Daha önceki versiyon çağrılacaktır. O versiyonda ise 'i' değişkeni // '1' idi ama '2' oldu. Ekrana da '2' yazdıracaktır. // OUTPUT => 112 } * Örnek 50, //.. int f() { std::cout << "f"; return 0; } int g() { std::cout << "g"; return 0; } void h(std::vector v) {} int main() { h( { f(), g() } ); // Derleyiciye bağlıdır DEĞİLDİR. Çünkü bir 'std::initializer_list' kullanılmış, // 'h' fonksiyonunun 'std::initializer_list' parametreli 'Ctor.' fonksiyonu // çağrılmıştır. 'std::initializer_list' kullanıldığı için de yazımdaki sıraya göre // fonksiyonlar çağrılacaktır. // OUTPUT => fg // Velev ki 'std::initializer_list' kullanılmasaydı; // İşte bu durumda hangi fonksiyonun önce çağrılacağı derleyiciye bağlı olacaktır. } * Örnek 51, //.. int y(int&) { return 1; } int y(int&&) { return 2; } template int f(T&& x) { return y(x); } template int g(T&& x) { return y(std::move(x)); } template int h(T&& x) { return y(std::forward(x)); } int main() { int i = 10; std::cout << f(i) << f(20); std::cout << g(i) << g(20); std::cout << h(i) << h(20); // i. 'f(i)' çağrısı sonrasında, şablon parametresi 'T' yerin 'int' gelecektir. 'x' ise 'int&&' türünden // olacaktır. Fakat fonksiyon bünyesinde bir İSİM kullanıldığından ki isim kullanılması her zaman // 'L-Value Expression' manasındadır, üstteki 'y' fonksiyonu çağrılacaktır. Dolayısıyla ekrana '1' yazacaktır. // ii. 'f(20)' ise yukarıdaki aynı sebepten dolayı ekrana yine '1' yazacaktır. // iii. 'g(i)' çağrısı sonrasında, şablon parametresi 'T' yerin 'int' gelecektir. 'x' ise 'int&&' türünden // olacaktır. Fakat fonksiyonun bünyesinde 'std::move()' çağrısı yapıldığından ifademiz artık // 'R-Value Expression' manasındadır. Bu nedenden dolayı alttaki 'y' fonksiyonu çağrılacak, ekranda '2' // yazacaktır. // iv. 'g(20)' ise yukarıdaki aynı sebepten dolayı ekrana yine '2' yazacaktır. // v. 'h(i)' çağrısı sonrasında, şablon parametresi 'T' yerin 'int' gelecektir. 'x' ise 'int&&' türünden // olacaktır. Fakat fonksiyonun bünyesinde 'std::forward<>()' çağrısı yapılmıştır ki bu çağrı aslında ifadenin // 'const' bilgisini ve 'Value Category' bilgisini korumasını sağlamaktadır. Dolayısıyla 'h(i)' çağrısı bir // 'L-Value Expression' ile yapıldığından üstteki 'y' fonksiyonu çağrılacaktır. Dolayısıyla ekrana '1' // yazacaktır. // vi. Yukarıdaki açıklanan 'std::forward<>()' çağrısından dolayı, 'h(20)' çağrısı da bir 'R-Value Expression' // ile yapıldığından alttaki 'y' fonksiyonu çağrılacaktır. Dolayısıyla ekrana '2' yazacaktır. } * Örnek 52, //.. int main() { using namespace std::string_literals; std::string s1("hello world", 5); // 'std::string' sınıfının 'data' parametreli 'Ctor.' fonksiyonuna çağrı yapılmıştır. Bu fonksiyon bir adres ve // adet bilgisi istemektedir. Yazının başından başlayarak ilk beş karakter, aslında 's1' içerisinde tutulacaktır. std::string s2("hello world"s, 5); // 'std::string' sınıfının 'sub-str' parametreli 'Ctor.' fonksiyonuna çağrı yapılmıştır. Bu fonksiyon bir // 'const std::string&' ve indis bilgisi istemektedir. Argüman olarak aldığı 'std::string' nesnesinin ilgili // indisinden başlayarak, yazının geri kalanını 's2' içerisine almaktadır. std::cout << "[" << s1 << "][" << s2 << "]"; // OUTPUT => [hello][ world] } * Örnek 53, //.. struct A { A() { std::cout << "A"; } ~A() { std::cout << "a"; } }; int main() { std::cout << "main"; return sizeof new A; // OUTPUT => main // 'sizeof' operatörünün operandı olan ifadeler HESAPLANMAZLAR. } * Örnek 54, //.. class C { public: C() = default; C(const C&) { std::cout << 1; } }; void f(std::initializer_list i) {} int main() { C c; std::initializer_list i{ c }; // Bu noktada 'Copy Ctor.' fonksiyonu çağrıldığı için ekrana '1' yazılacaktır. f(i); // Her ne kadar 'call-by-value' gibi gözükse de 'std::initializer_list' parametre türü olduğunda arka planda // 'call-by-reference' dönecektir. Dolayısıyla herhangi bir kopyalama söz konusu değildir. f(i); // Yukarıdaki aynı nedenden dolayı bu çağrıda da kopyalama YOKTUR. } * Örnek 55, //.. void f() { std::cout << "1"; } template struct B { void f() { std::cout << "2"; } }; template struct D : B { void g() { f(); } }; int main() { D d; // i. 'D' sınıfı, 'B' sınıfının 'int' açılımından kalıtım yoluyla elde edildi. d.g(); // ii. İsim arama kuralları gereği 'g' ismi 'D' sınıfı içerisinde aranacak, bulunacak. // Fakat 'g' içerisinde de 'f' fonksiyonu var. Şimdi; // Taban sınıfta da 'f' fonksiyonu var, // Global isim alanında da 'f' fonksiyonu var. // Eğer ortada şablon olmasaydı, çağrılacak fonksiyon kesinlikle TABAN SINIFTAKİ olacaktı. // Fakat şablon olduğu zaman şöyle bir kural devreye giriyor; İSİM HERHANGİ BİR ŞEKİLDE NİTELENMEMİŞSE, // TABAN SINIF İÇERİSİNDE İSİM ARANMIYOR. İşte bu nedenden dolayı global isim alanındaki bulunuyor ve çağrılıyor. // OUTPUT => 1 } * Örnek 56, //.. int main() { int i = std::numeric_limits::max(); std::cout << ++i; // İşaretli tam sayılarda taşma olması 'Tanımsız Davranış' oluşturur. } * Örnek 57, //.. void f(const std::string&) { std::cout << 1; } void f(const void*) { std::cout << 2; } int main() { f("foo"); // i. 'const char*' türünden 'void*' türüne dönüşüm 'Standart Conversion' fakat 'std::string' türüne dönüşüm // 'User-defined Conversion'. const char* bar = "bar"; f(bar); // ii. Yukarıdaki aynı neden ötürü. // OUTPUT => 22 } * Örnek 58, //.. struct Base { void f(int) { std::cout << "i"; } }; struct Derived : Base { void f(double) { std::cout << "d"; } }; int main() { Derived d; int i = 0; d.f(i); // 'f' ismi 'Derived' içerisinde aranacak ve bulunacak. // OUTPUT => d } * Örnek 59, //.. struct Base { void f(int) { std::cout << "i"; } }; struct Derived : Base { void f(double) { std::cout << "d"; } }; class A { public: virtual void f() { std::cout << "A"; } }; class B : public A { public: void f() { std::cout << "B"; } }; void g(A a) { a.f(); } int main() { Derived d; int i = 0; d.f(i); // d.Base::f(i); // Taban sınıftaki versiyonunu çağırmak için. std::cout << "\n----------------" << std::endl; B b; g(b); std::cout << "\n----------------" << std::endl; b.f(); /* # OUTPUT # d ---------------- A ---------------- B */ } * Örnek 60, //.. int main() { void* p = &p; // 'pointer' değişkenimizin kendi adresini tutması sentaks hatasına yol açmaz. // Kural gereği '=' operatörünün sol tarafındaki isim, sağ tarafında GÖRÜLÜR DURUMDADIR. std::cout << bool(p); // Tür dönüştürme operatörü kullanıldı. Bir 'pointer', 'bool' türüne dönüştürüldüğünde değerinin 'nullptr' // OLMADIĞI DİĞER DURUMLARDA 'true' DEĞERİNE DÖNÜŞÜR. Aksi durumda 'false'. // OUTPUT => 1 } * Örnek 61, //.. class show_id { public: ~show_id() { std::cout << id; } int id; }; int main() { delete[] new show_id[3]{ {0}, {1}, {2} }; // OUTPUT => 210 } * Örnek 62, //.. int main() { int i = 1; int const& a = i > 0 ? i : 1; // Bu ifadenin ikinci ('i') ve üçüncü ('1') operandları 'L-Value Expression' olsaydı, ifadenin kendisi // 'L-Value Expression' olacaktı. Fakat üçüncü operant 'R-Value Expression' olduğu için ifadenin kendisi // 'R-Value Expression' şeklindedir. // int const& a = 1; // Dolayısıyla ifade aslında bu şekildedir. i = 2; // 'i' artık '2' değerinde. std::cout << i << a; // OUTPUT => 21 } * Örnek 63, //.. using namespace std; int main() { int a = '0'; // 'a' değişkeni, '0' karakterinin ASCII tablodaki karşılığını tutmaktadır. Yani değeri '0'. char const& b = a; // Burada 'b' aslında geçici nesneye referanstır. // char temp = a; // const char b = temp; cout << b; // Ekrana '0' yazacaktır. a++; cout << b; // Ekrana '0' yazacaktır. // OUTPUT => 00 } * Örnek 64, //.. int x = 0; // i. 'x' değişkeni '0' değeri ile hayata geldi. class A { public: A() { std::cout << 'a'; // v. Ekrana 'a' yazısını yazacaktır. // xi. Ekrana tekrardan 'a' yazısını yazdıracaktır. // xii. Artık programın akışı bu 'if' bloğuna girmeyecektir çünkü 'x' değişkenimizin değeri '1'. // vi. 'x' değişkeni '0' değerinde olduğundan programın akışı buraya girecektir. if (x++ == 0) { // vii. Bu türden bir hata nesnesi fırlatılacaktır. Artık programın akışı buradan çıkacaktır. throw std::exception(); } } ~A() { std::cout << 'A'; } // xv. Son olarak da bunnu hayatı bitecektir. }; class B { public: B() { std::cout << 'b'; } // xiii. 'B' içindeki 'A' başarılı bir şekilde hayata geldiğinden, programın akışı buraya gelecektir ve // ekrana 'b' yazdıracaktır. ~B() { std::cout << 'B'; } // xiv. En son hayata gelen 'B' oldğundan, ilkin onun hayatı bitecektir. Ekrana 'B' yazdıracaktır. A a; // iv. Fakat önce veri elemanı olan 'a' hayata gelecektir. }; void foo() { static B b; } // iii. 'static' ömürlü 'B' sınıf türünden nesne hayata geldi. // x. Fakat 'b' değişkeninin hayata gelme süreci tamamlanmadığından, derleyici tekrardan 'B' türünden nesne // hayata getirmeye çalışacaktır. int main() { try { foo(); // ii. İş bu çağrı gerçekleşti. } catch (std::exception&) { std::cout << 'c'; // viii. Fırlatılan hata nesnesi yakalanacağı için programın akışı buraya gelecektir ve // ekrana 'c' yazacaktır. foo(); // ix. iş bu fonksiyon çağrısı yapılacaktır. } // OUTPUT => acabBA // HAYATA GELMEMİŞ NESNE İÇİN 'DTOR.' FONKSİYONU ÇAĞRILMAZ. } * Örnek 65, //.. struct X { X() { std::cout << "X"; } }; struct Y { Y(const X& x) { std::cout << "Y"; } void f() { std::cout << "f"; } }; int main() { //Y y( X() ); // MOST-VEXING PARSE: Function Declaration // i. Geri dönüş değerinin türü 'Y' sınıf türü. // ii. Fonksiyonumuzun ismi 'y'. // iii. Parametresi 'function-pointer' // Y y((X())); // Y y( X{} ); Y y{ X{} }; // i. 'X' sınıf türünden geçici nesne oluşturulduğundan ekrana 'X' yazacaktır. // ii. 'Y' sınıfı için 'Copy Ctor.' fonksiyonu çağrılacak ve ekrana 'Y' yazacaktır. // iii. İş bu fonksiyon ile de ekrana 'f' yazılacaktır. y.f(); // OUTPUT => XYf } * Örnek 66, //.. using namespace std; template void adl(T) { cout << "T"; } struct S {}; template void call_adl(T t) { adl(S()); adl(t); } void ad1(S) { cout << "S"; } int main() { call_adl(S()); // OUTPUT => TT } * Örnek 67, //.. int main() { // i. Operatör önceliğine göre 'sizeof' operatörü daha düşük öncelikte. int n = sizeof(0)["abcdefghij"]; // ii. Dolayısıyla ifade aslında bu şekilde. // int n = sizeof( (0)["abcdefghij"] ); // iii. ' (0)["abcdefghij"] ' ifadesi aslında ilk karakter olan 'a' karakterine karşılık gelmektedir. // 'char' türünün 'sizeof' değeri de '1' byte olduğundan, EKRANA '1' YAZMIŞTIR. // int n = sizeof( 'a' ); std::cout << n; // OUTPUT => 1 } * Örnek 68, //.. class MYclass{ public: MYclass() = default; MYclass(MYclass&&) = delete; }; MYclass FOO1() { return MYclass{}; } // 'MYclass' türünden geçici nesne döndürülmekte. // İş bu sebepten dolayı burada 'copy-ellision' bir zorunluluktur, 'Return-Value Optimization' // Bu yüzden SENTAKS HATASI DEĞİLDİR. MYclass FOO11() { MYclass mx; return mx; } // 'MYclass' türünden yerel bir nesne döndürmekte. 'copy-ellision', DERLEYİCİYE BAĞLI. // 'Named-Return-Value Optimization' BURADA YİNE TAŞIMA SEMANTİĞİ DEVREYE GİRECEKTİK. DOLAYISIYLA 'mx' NESNESİNİ // 'std::move()' İLE DÖNÜŞTÜRMEMİZE GEREK KALMIYOR. HATTA BAZI YERLERDE 'std::move()' İLE DÖNÜŞTÜRMEK BİR TAKIM // SAKINCALARA DA YOL AÇABİLMEKTE. // error: use of deleted function ‘constexpr MYclass::MYclass(const MYclass&)’ MYclass FOO111() { MYclass mx; return std::move(mx); } int main() { auto a = FOO1(); auto aa = FOO11(); auto aaa = FOO111(); return 0; } * Örnek 69, //.. std::unique_ptr func() { auto uptr = std::make_unique("necati"); return uptr; // BU ŞEKİLDE DÖNMEDE HİÇ BİR SAKINCA YOKTUR. 'moveable-only' değişkenleri böyle döndürmeye özen göstermeliyiz. // 'L-Value' to 'R-Value' DÖNÜŞÜMÜ MECBURİDİR. Fakat 'copy-ellision' ZORUNLU DEĞİL, derleyicilere bağlıdır. } int main() { /* # OUTPUT # */ auto a = func(); return 0; } * Örnek 70, //.. struct Base { void f(int) { std::cout << "1\n"; } }; struct Derived : Base { void f(double) { std::cout << "2\n"; } }; int main() { /* # OUTPUT # 2 */ Derived d; int i = 0; d.f(i); // i. Taban sınıf içerisindeki 'f' isimli fonksiyon 'virtual' değil. // ii. Her şeyin başı isim arama olduğundan, 'f' ismi ilk önce 'Derived' sınıfı içerisinde aranır ve bulunur. // iii. Kalıtım ise 'public' kalıtım çünkü 'struct' otomatik olarak 'public' kalıtım sağlamakta. // iv. Bütün bunların birleşmesi sonucunda da cevap '2'. return 0; } * Örnek 71, //.. int foo() { return 10; } struct foobar{ static int x; static int foo() { return 11; } }; int foobar::x = foo(); // 'static' veri elemanlarına ilk değer veren ifadelerde // ismi geçenler, eğer betimlenmemiş ise, ilk önce 'class-scope' içerisinde aranmaktadır. int main() { /* # OUTPUT # 11 */ std::cout << foobar::x << std::endl; return 0; } * Örnek 72, #include #include #define myFuncMacro(void) std::cout << "void myFunc(void) was called.\n"; void myFunc(void) { std::cout << "void myFunc(void) was called.\n"; } class myFuncClass{ public: void operator()(void) { std::cout << "void myFunc(void) was called.\n"; } }; int main() { /* # OUTPUT # void myFunc(void) was called. void myFunc(void) was called. void myFunc(void) was called. void myFunc(void) was called. void myFunc(void) was called. void myFunc(void) was called. void myFunc(void) was called. */ // Normal Fonksiyon Çağrısı myFunc(); // Fonksiyon Göstericisi Kullanarak auto myFuncPtr{ myFunc }; myFuncPtr(); // Fonksiyonel Makro Kullanarak myFuncMacro(); // Lambda Deyimi Kullanarak auto myFuncLambda = []{ std::cout << "void myFunc(void) was called.\n"; }; myFuncLambda(); // 'Functor' Kullanarak myFuncClass{}(); // 'std::function' Kullanarak std::function myFunction = myFunc; myFunction(); // 'std::bind' Kullanarak: std::bind(myFunc)(); return 0; } * Örnek 73, //.. class MoveOnly{ public: MoveOnly() = default; MoveOnly(MoveOnly&&) {} MoveOnly& operator=(MoveOnly&&) { return *this; } }; int main() { MoveOnly a; // MoveOnly b{a}; // error: use of deleted function 'constexpr MoveOnly::MoveOnly(const MoveOnly&)' MoveOnly b; // b = a; // error: use of deleted function 'constexpr MoveOnly::MoveOnly(const MoveOnly&)' MoveOnly c{ std::move(b) }; } * Örnek 74, //.. class CopyOnly{ public: CopyOnly() = default; CopyOnly(CopyOnly&& ) = delete; CopyOnly& operator=(CopyOnly&&) = delete; CopyOnly(const CopyOnly& ) {} CopyOnly& operator=(const CopyOnly&) { return *this; } }; int main() { CopyOnly a; CopyOnly b{a}; b = a; // CopyOnly c{ std::move(b) }; // error: use of deleted function 'CopyOnly::CopyOnly(CopyOnly&&)' } * Örnek 75, //.. template class Myclass{}; int main() { auto f = [](int x){ return x*x; }; // Myclass mx; // note: expected a type, got ‘f’ Myclass mx; // OK using g = int; Myclass my; // OK } * Örnek 76, //.. #include int& foo(int x) { return x; // MSVC : warning C4172: returning address of local variable or temporary: x } int main() { /* # OUTPUT # (5) : warning C4172: returning address of local variable or temporary: x cl : Command line warning D9002 : ignoring unknown option '-std=c++2b' Execution build compiler returned: 0 Program returned: 0 i. x : 31 ii. x : 62 iii. x : 62 */ int x = 31; auto& y = foo(x); std::cout << "i. x : " << x << std::endl; x += 31; std::cout << "ii. x : " << x << std::endl; y += 62; std::cout << "iii. x : " << x << std::endl; return 0; } * Örnek 77, //.. #include #include #include template std::ostream& operator<<(std::ostream& os, const std::array& array) { os << "[ " << array.front() << ", "; for(std::size_t i{1}; i < size - 1; ++i) os << array[i] << ", "; os << array.back() << " ]\n"; return os; } template std::ostream& operator<<(std::ostream& os, const std::vector& array) { os << "[ " << array.front() << " | "; for(std::size_t i{1}; i < array.size() - 1; ++i) os << array[i] << " | "; os << array.back() << " ]\n"; return os; } int main() { std::array arx{ 1, 2, 3, 4, 5 }; std::cout << arx; std::vector ary{ 5, 6, 7, 8, 9 }; std::cout << ary << std::endl; return 0; } * Örnek 78, //.. #include #include struct Myclass{ Myclass(int a, int b, int c) : _a(a), _b(b), _c(c) {} int _a, _b, _c; }; Myclass funcOne(int a, int b, int c) { return Myclass{a, b, c}; } Myclass funcTwo(int a, int b, int c) { return {a, b, c}; } template Myclass funcThree(Args&& ... args) { return Myclass{ std::forward(args)... }; } std::ostream& operator<<(std::ostream& os, const Myclass& other) { return os << "[ " << other._a << ", " << other._b << ", " << other._c << " ]"; } int main() { /* # OUTPUT # [ 1, 2, 3 ] [ 10, 20, 30 ] [ 100, 200, 300 ] */ auto objOne{ funcOne(1, 2, 3) }; std::cout << objOne << std::endl; auto objTwo{ funcTwo(10, 20, 30) }; std::cout << objTwo << std::endl; auto objThree{ funcThree(100, 200, 300) }; std::cout << objThree << std::endl; return 0; } * Örnek 79, //.. /* * Creating a temporary variable, * Integral-promotion, * Move semantics */ #include #include #include uint16_t doit(uint16_t&& value) { return value * 160; } uint32_t doit(uint32_t&& value) { return value * 320; } int main() { uint16_t value16 = 1; uint32_t value32 = 1; printf("(%d)\n", doit(value16)); // OUTOUT => (320) printf("(%d)\n", doit(value32)); // OUTOUT => (160) return 0; } * Örnek 80, //.. /* * Find the max_of_four */ #include #include int max_of_four(int a, int b, int c, int d) { return std::max(a, std::max(b, std::max(c, d))); } int main() { int a, b, c, d; scanf("%d %d %d %d", &a, &b, &c, &d); int ans = max_of_four(a, b, c, d); printf("%d", ans); return 0; } * Örnek 81, //.. /* * https://www.hackerrank.com/challenges/variable-sized-arrays/problem */ #include #include #include #include #include using namespace std; int main() { unsigned int rows, questions; cin >> rows >> questions; vector> vectorsOfData; for (unsigned int indexOuter{}; indexOuter < rows; ++indexOuter) { unsigned int iVecSize; cin >> iVecSize; vector iVec; for (unsigned int indexInner{}; indexInner < iVecSize; ++indexInner) { unsigned int iVecValue; cin >> iVecValue; iVec.push_back(iVecValue); } vectorsOfData.push_back(iVec); } unsigned int whichArray, whichColomn; for (unsigned int index = 0; index < questions; ++index) { cin >> whichArray >> whichColomn; cout << vectorsOfData[whichArray][whichColomn] << "\n"; } return 0; } * Örnek 82, //.. #include struct A{ A() { f(); } virtual void f() && { std::cout << "void f::A() &&" << std::endl; } virtual void f() & { std::cout << "void f::A() &" << std::endl; } }; struct B : public A{ B() { f(); } virtual void f() && { std::cout << "void f::B() &&" << std::endl; } virtual void f() & { std::cout << "void f::B() &" << std::endl; } }; int main() { /* # OUTPUT # void f::A() & void f::B() & void f::B() && */ B{}.f(); } * Örnek 83, //.. /* * Rule of Four : A Dtor, A Copy Ctor, A Move Ctor & Assignment Operator by Value */ class NaiveVector{ public: // Copy Ctor. NaiveVector(const NaiveVector& rhs) { size_ = rhs.size_; ptr_ = new int[rhs.size_]; std::copy(rhs.ptr_, rhs.ptr_ + size_, ptr_); } // Move Ctor. NaiveVector(NaiveVector&& rhs) noexcept { size_ = std::exhange(rhs.size_, 0); ptr_ = std::exhange(rhs.ptr_, nullptr); } // An Assignment Operator by Value NaiveVector& operator=(NaiveVector rhs) noexcept { rhs.swap(*this); return *this; } // Dtor. ~NaiveVector() noexcept { delete[] ptr_; } // An ADL overload "swap" function. This function is not a MEMBER FUNCTION. friend void swap(NaiveVector& a, NaiveVector& b) noexcept { a.swap(b); } // A member "swap" function. void swap(NaiveVector& rhs) noexcept { using std::swap; swap(ptr_, rhs.ptr_); swap(size_, rhs.size_); } private: size_t size_; int* ptr_; }; * Örnek 84, //.. /* * Closer-to-Rule-of-Zero */ class NaiveVector{ public: // Copy Ctor. NaiveVector(const NaiveVector& rhs) { size_ = rhs.size_; uptr_ = std::make_unique(rhs.size_); std::copy(rhs.uptr_, rhs.uptr_ + size_, uptr_); } // Move Ctor. NaiveVector(NaiveVector&& rhs) noexcept = default; // An Assignment Operator by Value NaiveVector& operator=(NaiveVector rhs) noexcept { rhs.swap(*this); return *this; } // Dtor. ~NaiveVector() noexcept = default; // An ADL overload "swap" function. This function is not a MEMBER FUNCTION. friend void swap(NaiveVector& a, NaiveVector& b) noexcept { a.swap(b); } // A member "swap" function. void swap(NaiveVector& rhs) noexcept { using std::swap; swap(ptr_, rhs.ptr_); swap(size_, rhs.size_); } private: size_t size_; std::unique_ptr uptr_; }; * Örnek 85, //.. /* * True-Rule-of-Zero => "Rule of Zero" is about resource management, not about * how do I create an object. For that reason, we can have multiple ctor. functions * with different parameters. */ class NaiveVector{ public: // Copy Ctor. NaiveVector(const NaiveVector& rhs) = default; // Move Ctor. NaiveVector(NaiveVector&& rhs) noexcept = default; // An Assignment Operator by Value NaiveVector& operator=(NaiveVector rhs) noexcept { rhs.swap(*this); return *this; } /* * However, we can also write "NaiveVector& operator=(NaiveVector&& rhs) = default;" * and "NaiveVector& operator=(const NaiveVector& rhs) = default;" as an alternative. * Because, if we have multiple data members, the defaulted assignment operators will * assign them member-by-member (a.k.a member-wise assignment). This may cause some * problems. */ // Dtor. ~NaiveVector() noexcept = default; // An ADL overload "swap" function. This function is not a MEMBER FUNCTION. friend void swap(NaiveVector& a, NaiveVector& b) noexcept { a.swap(b); } // A member "swap" function. void swap(NaiveVector& rhs) noexcept { vec_.swap(rhs.vec_); } private: std::vector vec_; }; * Örnek 86, //.. /* * Passing lambdas to template functions. * Capture-all-by-value in lambdas. */ #include template auto myFoo(T t) { return t(); } int main() { double divided = 100.; int divisor = 3; auto myLambda = [=](){ return divided / divisor; }; std::cout << "[" << myLambda() << "]\n"; // [33.3333] std::cout << "[" << myFoo(myLambda) << "]\n"; // [33.3333] return 0; } * Örnek 87, /* * Run Time Type Polymorphism : using 'virtual' keyword in Base class and * Base class Dtor. */ #include class Base{ public: Base() { std::cout << "Base::Base()\n"; } virtual void Activate() { std::cout << "Base::Activate()\n"; } virtual ~Base() { std::cout << "Base::~Base()\n"; } }; class Derived : public Base{ public: Derived() { std::cout << "Derived::Derived()\n"; } void Activate() override { std::cout << "Derived::Activate()\n"; } ~Derived() { std::cout << "Derived::~Derived()\n"; } }; int main() { /* # OUTPUT # Base::Base() Derived::Derived() Derived::Activate() Derived::~Derived() Base::~Base() */ Base* myBasePtr = new Derived; myBasePtr->Activate(); delete myBasePtr; } * Örnek 88, //.. /* * An Alternative for Run Time Type Polymorphism : Forbiding the function * calls using Base class type pointers. */ #include class Base{ public: Base() { std::cout << "Base::Base()\n"; } void Activate() { std::cout << "Base::Activate()\n"; } protected: ~Base() { std::cout << "Base::~Base()\n"; } }; class Derived : public Base{ public: Derived() { std::cout << "Derived::Derived()\n"; } void Activate() { std::cout << "Derived::Activate()\n"; } ~Derived() { std::cout << "Derived::~Derived()\n"; } }; int main() { /* # OUTPUT # : In function 'int main()': :37:12: error: 'Base::~Base()' is protected within this context 37 | delete myBasePtr; | ^~~~~~~~~ :11:9: note: declared protected here 11 | ~Base() { std::cout << "Base::~Base()\n"; } | ^ */ Base* myBasePtr = new Derived; myBasePtr->Activate(); delete myBasePtr; // err line. /* # OUTPUT # Base::Base() Derived::Derived() Derived::Activate() Derived::~Derived() Base::~Base() */ Derived* myDerivedPtr = new Derived; myDerivedPtr->Activate(); delete myDerivedPtr; } * Örnek 89, //.. /* * An Alternative for Run Time Type Polymorphism : CRTP */ #include template class Base{ public: void Activate() { T& derived = static_cast(*this); derived.DerivedActivate(); } }; class Derived : public Base { public: void DerivedActivate() { std::cout << "Derived, from Base\n"; } }; class DerivedDerived : public Base { public: void DerivedActivate() { std::cout << "DerivedDerived, from Base\n"; } }; int main() { Base typeOne; typeOne.Activate(); // OUTPUT => Derived, from Base Base typeTwo; typeTwo.Activate(); // OUTPUT => DerivedDerived, from Base } * Örnek 90, //.. /* * Template examples */ #include #include #include #include // Allias Template template using RemoveReference_t = typename std::remove_reference::type; // Allias Template template using gset = std::set>; // Class Template template struct X { constexpr static int value = 500; }; // Template template constexpr auto X_v = X::value; int main() { /* # OUTPUT # ---------- 5 4 3 2 1 ---------- 31 ---------- 500 ---------- */ std::cout << "----------" << std::endl; // Allias Template gset x_Allias{ 1, 2, 3, 4, 5, 5, 4, 3, 2, 1}; for (auto index : x_Allias) { std::cout << index << std::endl; } std::cout << "----------" << std::endl; // Allias Template RemoveReference_t x_Allias_Two{31}; std::cout << x_Allias_Two << std::endl; std::cout << "----------" << std::endl; // Class Template constexpr auto ival = X_v; std::cout << ival << std::endl; std::cout << "----------" << std::endl; } * Örnek 91, /* A pointer to private data member of a class. */ #include class MyClass { int i{21}; public: void print(void) { std::cout << "[" << i << "]" << std::endl; } }; int main() { /* # OUTPUT # [21] [21] [32] */ MyClass obj; obj.print(); int* ptr; ptr = (int*)&obj; // ptr = static_cast(&obj); // error: invalid static_cast from type ‘MyClass*’ to type ‘int*’ std::cout << "[" << *ptr << "]" << std::endl; *ptr = 32; obj.print(); return 0; }