C++ Constructor

15 minute read

Construct -> inşa etmek, kurmak

Constructor -> inşa eden, kurucu

  • Constructor hakkında bilmemiz gereken bazı bilgiler: (Yazının devamında bunları inceleyeceğiz)
  1. Constructor nesneyi hayata hazırlar.
  2. Her sınıfın constructorı mutlaka var.
  3. Ben constructor yazmassam benim yerime derleyici yazıyor.
  4. Constructor sınıf ismi ile aynı olmalıdır.
  5. Constructor geri dönüş kavramı yoktur. (void değil karıştırılmamalı)
  6. Constructor NON-STATIC üye fonksiyonudur.
  7. Constructor const OLAMAZ.
  8. Constructor OVERLOAD edilebilir.
  • Bir sınıf nesnesi için bir bellek alanı elde etmemiz onu kullanılabilir bir sınıf yapmıyor. Kullanılabilir olması için ona bir ilk değer vermek gerekiyor.

  • Bir nesne hayata geldiğinde o nesnenin kullanılabilmesi için bazı kaynaklar edinmesi gerekiyor. Yani sadece ilk değer vermek olarak düşünmeyin, bazıları kaynak edinecekler.

  • C++ dilinde sınıflar için bazı fonksiyonlar var ki mutlaka olmak zorunda. Bu fonksiyonlara özel fonksiyonlar diyoruz. Yani bu fonksiyonlar biz yazarsak bizimkiler kullanılacak, biz yazmassak derleyeci bizim yerimize yazıp kullanacak. Constructor da özel fonksiyonlardan birisi.

  • Constructor için keyfi isim veremiyoruz. Yani bu isim class ismi ile aynı olmak zorunda. Derleyici constructor olup olmadığını sınıf ismi ile aynı olup olmadığına bakarak anlıyor.

  • Constructor’ın geri dönüş değeri gibi bir kavram yok. Yani void değil. Karıştırılmasın geri dönüş değeri diye bir kavram yok.


Constructor static üye fonksiyon mu yoksa non-static üye fonksiyon mu?

  • Constructor non-static üye fonksiyonudur. Çünkü nesnemize ilk değer vereceğine göre büyük olasıklıkla veri elemanlarına değerler yerleştirecek. Veri elemanlarına değer yerleştirmesi için nesnemizin adresini alması lazım. Nesnemizin adresini alması demek this göstericisinin olması demek.

Constructor sınıfın public bölümünde olmak zorunda mı?

  • Hayır böyle bir zorunluluk yok.

  • Eğer sınıfın private bölümüne koyarsak, derleyici tarafından çağırıldığı zaman yine sentaks hatası olur. Hatırlarsak clientlar sınıfın sadece public bölümüne erişebiliyorlardı. Hata olan constructor’ın private olması değil, private bir fonksiyonun çağırılması.

  • Constructor’ı private bölümüne yazacağımız özel bazı senaryolar var. (Örnek: Singleton Pattern)

 1#include <iostream>
 2
 3// Private Constructor
 4class Myclass {
 5  Myclass();
 6public:
 7  void func();
 8};
 9
10
11int main()
12{
13  Myclass m; //gecersiz cunku constructor private
14  // error: calling a private constructor of class 'Myclass'
15
16  return 0;
17}

Default Constructor (Varsayılan Kurucu İşlev)

  • Parametre değişkeni yoksa yada tüm parametre değişkenleri varsayılan argüman alıyorsa bu default constructor

  • Argüman göndermeden çağırılabilen constructorlara default constructor diyoruz


Argüman Nedir?

  • Fonksiyon çağrılarıyla fonksiyonlara gönderilen ifadelere arguman yada actual parameter denir.

  • Biz hiçbir constructor yazmassak derleyici bize non-static inline public bir constructor yazar.


non-static ne demek?

  • static keywordu olmayan, yani this göstericisine sahip olan demek

  • Derleyicinin yazdığı constructor ın static olma imkanı yok, private olma imkanı yok


inline, fonksiyonlar için 2 farklı model var.

  1. Biz bir fonksiyona çağrısı yapıyoruz. Derleyici bu fonksiyona giriş çıkış kodlarını üretiyor fakat bu fonksiyonun kendi kodunun bu koda bağlanması işini linker’a havale ediyor. Peki bunu nasıl yapıyor? external reference yazıyor.

  2. inline fonksiyon dediğimiz şöyle, derleyici fonksiyonun tanımını da görücek, fonskiyonun tanımını gördüğü için fonksiyonu derleyecek object kodunu doğrudan çağırdığı yere gömücek. Yani burada artık linker bypass edilmiş oluyor. inline yapmakla derleyiciye şunu söylüyoruz, derleyici sen linker’i felan bırak gel bu işi aramızda halledelim.

  • inline fonksiyon ile inlined fonksiyonu birbirine karıştırmamak gerek. Bir fonksiyona inline demek böyle bir rica da bulunmak demek. Derleyici bu ricayı yerine getirebiliyorsa artık o fonksiyon inlined olucak.

  • Ama semantik olarak şöyle bir avantaj olacak. Derleyici bunu yerine getirse de getirmese de client tarafından kodla bunun bir alakası yok. Nasıl fonksiyon çağırıyorsak öyle çağırıcaz.

  • Constructor const olamaz

  • Constructor overload edilebilir, fazlaca karşılaşılan bir senaryo

 1// Constructor Overload
 2
 3#include <string>
 4#include <cstring>
 5
 6
 7class Date {
 8public:
 9    Date();
10    Date(int d, int m, int y);
11    Date(const std::string &); // tarih formatini bir yazi seklinde iletiyoruz
12};
13//Constructor Overload
14
15#include <string>
16#include <cstring>
17
18
19class Triangle {
20
21public:
22    Triangle(double d1, double d2, double d3);
23    Triangle(double base, double height);
24};

Constructor explicit olarak çağrılamaz. (constructor ismi ile çağırılamaz)

 1// Constructor Hatalı Çağırma
 2
 3#include <iostream>
 4
 5using namespace std;
 6
 7class Myclass {
 8
 9public:
10    Myclass(){}
11    Myclass(int, int);
12};
13
14
15int main()
16{
17    Myclass m;
18
19    m.M(); // gecersiz
20    // error: cannot refer to type member 'Myclass' in 'Myclass' with '.'
21
22    return 0;
23}
24//Constructor C++11 Default Keyword
25#include <iostream>
26
27using namespace std;
28
29class Myclass {
30
31public:
32    Myclass(int);
33};
34
35
36int main()
37{
38    Myclass m; // hata boyle bir constructor yok
39    // no matching constructor for initialization of 'MyClass'
40
41    return 0;
42}
43
44// Cozum -> C++11 ile gelen default keywordu
45// Myclass(){}; yada Myclass = default(); // c++11

Function overload kuralları burada tamamen geçerli

 1// Function Overload
 2Myclass(long);
 3Myclass(float);
 4//main….
 5Myclass m(10); //embiguity
 6// Constructor C++11
 7
 8#include <string>
 9#include <cstring>
10
11
12class Myclass {
13
14public:
15    Myclass(int);
16    Myclass();
17
18
19};
20
21
22int main()
23{
24    Myclass m1;  //default constructor
25    Myclass m2{};  //default constructor  - C++11
26    Myclass m3();  //function declaration
27    Myclass m4 = Myclass();
28    Myclass m5 = Myclass{};
29
30    return 0;
31}

Nesne ne zaman hayata başlarsa constructor o zaman çağırılıyor.

  • C++ diğer dillerden farklılığı, primitive nesneler gibi, yerel nesneler oluşturabiliyoruz. Yani otomatik ömürlü, static ömürlü ve dinamik ömürlü nesne oluşturabiliyoruz.
 1// Constructor
 2#include <iostream>
 3
 4using namespace std;
 5
 6class Myclass {
 7
 8public:
 9    Myclass();
10};
11
12/////
13Myclass::Myclass()
14{
15    cout << "Myclass default constructor" << endl;
16}
17
18void func()
19{
20    Myclass m; // stack yer alan, default contructor cagirilacak
21}
22
23int main()
24{
25    for (int k = 0; k < 10; k++)
26        func();
27
28    return 0;
29}
30/*
31Myclass default constructor
32Myclass default constructor
33Myclass default constructor
34Myclass default constructor
35….
36*/
37// Default Constructor
38
39#include <iostream>
40
41using namespace std;
42
43class Myclass {
44
45public:
46    Myclass();
47};
48
49/////
50Myclass::Myclass()
51{
52    cout << "Myclass default constructor" << endl;
53}
54
55void func()
56{
57    Myclass m1, m2; // hem m1 hemde m2 icin cagirilacak ayri ayri
58    cout << "************************" << endl;
59}
60
61int main()
62{
63    for (int k = 0; k < 10; k++)
64        func();
65
66    return 0;
67}
68
69/*
70Myclass default constructor
71Myclass default constructor
72"************************"
73Myclass default constructor
74Myclass default constructor
75*/

Referans demek nesne demek değil

 1#include <iostream>
 2
 3using namespace std;
 4
 5class Myclass {
 6
 7public:
 8    Myclass();
 9};
10
11/////
12Myclass::Myclass()
13{
14    cout << "Myclass default constructor" << endl;
15}
16
17
18int main()
19{
20    Myclass m1; // 1 kere constructor cagirilir
21    // Myclass default constructor
22    Myclass &r1 = m1; // referans demek nesne demek degil
23    Myclass &r2 = m1; // referans bir nesnenin yerine gecen isim
24
25    return 0;
26}

Pointer — Constructor

 1#include <iostream>
 2
 3using namespace std;
 4
 5class Myclass {
 6
 7public:
 8    Myclass();
 9};
10
11/////
12Myclass::Myclass()
13{
14    cout << "Myclass default constructor" << endl;
15}
16
17
18int main()
19{
20    Myclass *ptr; // constructor cagrisi yok, bu bir pointer, bir instance
21    // olusturulmadigi surece constructorin cagrisina neden olmaz
22
23    return 0;
24}
25// Constructor
26
27#include <iostream>
28
29using namespace std;
30
31class Myclass {
32
33public:
34    Myclass();
35};
36
37/////
38Myclass::Myclass()
39{
40    cout << "Myclass default constructor" << endl;
41}
42
43
44int main()
45{
46    Myclass a[10]; // 10 kere constructor cagirilacak, her elemani icin
47
48    return 0;
49}

Static ömürlü nesneler main’den önce çağırılır

 1#include <iostream>
 2
 3using namespace std;
 4
 5class Myclass {
 6
 7public:
 8    Myclass();
 9};
10
11/////
12Myclass::Myclass()
13{
14    cout << "Myclass default constructor" << endl;
15}
16
17Myclass g; // global bir nesne, ömrü static
18// static omurlu nesneler main den önce cagirilirlar
19
20int main()
21{
22    cout << "main basliyor" << endl;
23
24    return 0;
25}

Static Yerel Sınıf Nesneleri

 1#include <iostream>
 2
 3using namespace std;
 4
 5class Myclass {
 6
 7public:
 8    Myclass();
 9};
10
11/////
12Myclass::Myclass()
13{
14    cout << "Myclass default constructor" << endl;
15}
16
17void func()
18{
19    static Myclass m;  //statik yerel sinif nesneleri icin
20    //eger bu fonksiyon cagrilmazsa m hayata gelmez
21}
22
23int main()
24{
25
26    return 0;
27}
28#include <iostream>
29
30using namespace std;
31
32class Myclass {
33
34public:
35    Myclass();
36};
37
38/////
39Myclass::Myclass()
40{
41    cout << "Myclass default constructor" << endl;
42}
43
44void func()
45{
46    static Myclass m;
47}
48
49int main()
50{
51    cout << "main basliyor" << endl;
52    cout << "func cagriliyor " << endl;
53    func(); // constructor cagirilacak
54    cout << "main devam ediyor" << endl;
55    cout << "func bir kez daha cagriliyor " << endl;
56    func(); // contructor yazisi cikmaz, artik 2. kez cagirdigimizda hayata gelmiyor
57    // static nesneler hayata 1 kere gelir
58    cout << "func bir kez daha cagriliyor " << endl;
59    func();
60
61    return 0;
62}
63

New Operatörü

  • Dinamik nesne yaratılması için heap te bir alan yaratılması gerekiyor. Bu alanı tahsis eden operatör new (bu bir fonksiyonun ismi) (new bir operatör, operator new fonksiyon)

  • new operatörü önce operator new çağırıyor. Heap te bir alan elde ediliyor. O fonksiyon malloc un eşdeğeri bir fonksiyon. Yani size of myclass kadar yer ayırıyor. O adresi void olarak döndürüyor. Derleyici void myclass* dönüştürerek o adres için constructor çağırıyor.

  • Constructor çağırılmasını sağlayan pointer değil. new operatörünün kullanılması.

 1// New Operator
 2#include <iostream>
 3
 4using namespace std;
 5
 6class Myclass {
 7
 8public:
 9    Myclass();
10};
11
12/////
13Myclass::Myclass()
14{
15    cout << "Myclass default constructor" << endl;
16}
17
18int main()
19{
20    cout << "main basliyor" << endl;
21
22    Myclass *ptr = new Myclass;
23    // main basliyor
24    // MyClass default constructor
25
26    return 0;
27}

2 tane new operatörü var. tekil new operatörü && [] new operatörü

 1// New Operator
 2#include <iostream>
 3
 4using namespace std;
 5
 6class Myclass {
 7
 8public:
 9    Myclass();
10};
11
12/////
13Myclass::Myclass()
14{
15    cout << "Myclass default constructor" << endl;
16}
17
18int main()
19{
20    cout << "main basliyor" << endl;
21
22    Myclass *ptr = new Myclass[5];
23    // 5 tane MyClass nesnesi hayata gelir
24    // Constructor 5 kere cagirilir
25
26    ////
27
28    return 0;
29}

Non-Static Function

 1#include <iostream>
 2
 3using namespace std;
 4
 5class Myclass {
 6
 7public:
 8    Myclass();
 9};
10
11/////
12Myclass::Myclass()
13{
14    cout << "Myclass default constructor" << endl;
15    cout << "this    = " << this << endl;
16}
17
18int main()
19{
20    Myclass m1;
21
22    cout << "&m1     = " << &m1 << endl;
23
24    return 0;
25}
26// Uniform Initializer
27
28#include <iostream>
29
30using namespace std;
31
32class Myclass {
33
34public:
35    Myclass();
36};
37
38/////
39Myclass::Myclass()
40{
41    cout << "Myclass default constructor" << endl;
42    cout << "this    = " << this << endl;
43}
44
45int main()
46{
47    Myclass *ptr{new Myclass};
48
49    cout << "ptr     = " << ptr << endl;
50
51    return 0;
52}
53// Pointer Aritmetiği
54#include <iostream>
55
56using namespace std;
57
58class Myclass {
59    int a[4];
60public:
61    Myclass();
62};
63
64/////
65Myclass::Myclass()
66{
67    cout << "Myclass default constructor" << endl;
68    cout << "this    = " << this << endl;
69}
70
71int main()
72{
73    Myclass x[4];
74
75    return 0;
76}

C++03 ve C++11 Kullanımları

 1#include <iostream>
 2
 3using namespace std;
 4
 5class Myclass {
 6public:
 7    Myclass(int);
 8};
 9
10/////
11int main()
12{
13    Myclass *p1 = new Myclass(12); //C++03
14    Myclass *p2 = new Myclass{45}; //C++11
15
16
17
18    return 0;
19}