Yükleniyor...

C++ Constructor ve Destructor Mantığı

C++ constructor ve destructor kullanımını öğrenin. Nesne yaşam döngüsü, başlatma ve kaynak yönetimi örneklerle açıklanıyor.

C++’ta her sınıf, bir nesne oluşturulurken ve yok edilirken özel metotlara sahiptir: Constructor (kurucu) ve Destructor (yıkıcı). Constructor nesneyi ilk kullanıma hazır hale getirir, Destructor ise belleği temizler. Bu yapı, RAII (Resource Acquisition Is Initialization) prensibinin temelini oluşturur.


1. Constructor Nedir?

Constructor, bir sınıfın nesnesi oluşturulduğunda otomatik olarak çağrılan özel bir metottur. Amacı, değişkenleri başlatmak ve gerekli kaynakları hazırlamaktır.


class Book {
private:
    string title;
    int pages;

public:
    // Varsayılan constructor
    Book() {
        title = "Bilinmeyen";
        pages = 0;
        cout << "Varsayılan constructor çağrıldı." << endl;
    }

    // Parametreli constructor
    Book(string t, int p) {
        title = t;
        pages = p;
        cout << "Parametreli constructor çağrıldı." << endl;
    }

    void Display() {
        cout << "Kitap: " << title << " (" << pages << " sayfa)" << endl;
    }
};

Nesne oluşturulduğunda constructor otomatik çalışır:


int main() {
    Book b1;
    Book b2("C++ Programlama", 900);

    b1.Display();
    b2.Display();
}

2. Destructor Nedir?

Destructor, nesne ömrü sona erdiğinde çağrılan özel metottur. Belleği serbest bırakmak, dosyaları kapatmak gibi temizlik işlemleri için kullanılır.


class Book {
public:
    Book() {
        cout << "Constructor çalıştı." << endl;
    }

    ~Book() {
        cout << "Destructor çalıştı." << endl;
    }
};

int main() {
    Book b;
} // main bitince destructor otomatik çağrılır

Çıktı:


Constructor çalıştı.
Destructor çalıştı.

Destructor otomatik çağrıldığı için manuel olarak çağrılmamalıdır.


3. Book Örneği: Genişletilmiş Constructor ve Destructor

Şimdi Book sınıfını daha gerçekçi hale getirelim. İçinde dinamik olarak ayrılmış veriler bulunsun (örneğin kitap açıklaması). Böylece destructor’ın neden önemli olduğunu görebiliriz.


#include <iostream>
#include <string>
using namespace std;

class Book {
private:
    string title;
    int pages;
    string *description; // Dinamik bellek

public:
    // Constructor
    Book(string t, int p, string d)
        : title(t), pages(p) {
        description = new string(d);
        cout << "Book constructor: " << title << endl;
    }

    // Destructor
    ~Book() {
        cout << "Book destructor: " << title << endl;
        delete description; // Dinamik bellek serbest bırakılır
    }

    void Display() const {
        cout << "Kitap: " << title << " (" << pages << " sayfa)" << endl;
        cout << "Açıklama: " << *description << endl;
    }
};

int main() {
    Book b1("1984", 328, "Distopik bir roman.");
    b1.Display();
}

Çıktı:


Book constructor: 1984
Kitap: 1984 (328 sayfa)
Açıklama: Distopik bir roman.
Book destructor: 1984

Destructor, nesne main()’in sonunda yaşam döngüsünü tamamladığında çağrılır ve new ile ayrılmış belleği geri serbest bırakır.


4. Constructor Overloading (Aşırı Yükleme)

Aynı sınıfta birden fazla constructor tanımlanabilir. Parametre sayısına göre uygun olan çağrılır.


class Book {
private:
    string title;
    int pages;

public:
    Book() : title("Bilinmeyen"), pages(0) {}
    Book(string t) : title(t), pages(100) {}
    Book(string t, int p) : title(t), pages(p) {}

    void Display() {
        cout << "Kitap: " << title << " (" << pages << " sayfa)" << endl;
    }
};

int main() {
    Book b1;
    Book b2("C++ 101");
    Book b3("Design Patterns", 450);

    b1.Display();
    b2.Display();
    b3.Display();
}

5. Copy Constructor (Kopya Kurucu)

Varsayılan olarak C++ bir copy constructor oluşturur, ancak dinamik bellek kullanıyorsak kendi kopya constructor’ımızı tanımlamalıyız.


class Book {
private:
    string title;
    string *desc;

public:
    Book(string t, string d) {
        title = t;
        desc = new string(d);
        cout << "Constructor: " << title << endl;
    }

    // Kopya constructor
    Book(const Book &other) {
        title = other.title;
        desc = new string(*other.desc); // derin kopya
        cout << "Copy constructor: " << title << endl;
    }

    ~Book() {
        delete desc;
        cout << "Destructor: " << title << endl;
    }

    void Display() {
        cout << title << " - " << *desc << endl;
    }
};

int main() {
    Book b1("C++ Primer", "Temel seviye kılavuz");
    Book b2 = b1; // copy constructor çağrılır
    b2.Display();
}

Derin kopyalama (deep copy) yapılmazsa iki nesne aynı belleği paylaşır, bu da destructor çağrıldığında “çifte delete” hatasına neden olur.


6. Book Sistemi – Yaşam Döngüsü Takibi

Aşağıdaki örnek, bir kitap nesnesinin oluşturulma ve yok edilme sırasını gösterir. Bu, constructor ve destructor’ın gerçek yaşam döngüsünü anlamak için idealdir.


#include <iostream>
#include <string>
using namespace std;

class Author {
public:
    Author(string n) { cout << "Author oluşturuldu: " << n << endl; }
    ~Author() { cout << "Author yok edildi." << endl; }
};

class Book {
private:
    string title;
    Author author;

public:
    Book(string t, string a) : title(t), author(a) {
        cout << "Book oluşturuldu: " << title << endl;
    }

    ~Book() {
        cout << "Book yok edildi: " << title << endl;
    }
};

int main() {
    Book b("Hayvan Çiftliği", "George Orwell");
}

Çıktı:


Author oluşturuldu: George Orwell
Book oluşturuldu: Hayvan Çiftliği
Book yok edildi: Hayvan Çiftliği
Author yok edildi.

Gördüğünüz gibi önce Author constructor’ı çağrılır, ardından Book constructor’ı. Yok edilirken tam tersi sıra uygulanır (önce Book, sonra Author). Bu, composition (bileşim) ilişkilerinde C++’ın yaşam döngüsü sırasını gösterir.


7. TL;DR

  • Constructor → Nesne oluşturulurken otomatik çağrılır.
  • Destructor → Nesne yaşam döngüsü bittiğinde otomatik çağrılır.
  • Constructor overload edilebilir, Destructor edilemez.
  • Dinamik bellek varsa Destructor mutlaka delete çağırmalıdır.
  • Copy constructor derin kopya (deep copy) yapmalıdır.
  • Oluşturulma sırası: önce alt bileşenler, sonra sınıf; Yok edilme sırası: önce sınıf, sonra alt bileşenler.
  • Tüm örnekler Visual Studio 2022 veya GCC 11+ ortamında çalıştırılabilir.

İlişkili Makaleler