Menu
CoddyTech

Kopya Yapıcı

Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 20 / 104.

Kopyalama kurucusu, mevcut bir nesnenin kopyası olarak yeni bir nesne oluşturur. Bir nesneyi aynı türden başka bir nesneden başlatırken, bir nesneyi değere göre aktarırken veya değere göre döndürürken çağrılır.

Kopyalama kurucusu, aynı sınıftan bir nesneye const referans alır. Bunun bir referans olması gerekir: other değerle geçirilseydi, kendisinin de kopyalanması gerekirdi; bu da kopyalama kurucusunun tekrar tekrar, sonsuza dek çağrılmasına yol açardı. const olmasının nedeni, kopyalamanın özgün nesneyi asla değiştirmemesi gerektiğidir:

class Player {
    std::string name;
    int health;
public:
    Player(std::string n, int h) : name(n), health(h) {}
    
    // Kopyalama kurucusu
    Player(const Player& other) {
        name = other.name;
        health = other.health;
    }
};

Player original("Hero", 100);
Player copy = original;    // Kopyalama kurucusu çağrıldı
Player another(original);  // Kopyalama kurucusunu da çağırır

Bir kopyalama kurucusu tanımlamazsan, derleyici her üyenin değerini doğrudan kopyalayan bir sığ kopya oluşturur. Bu, basit türlerde sorunsuz çalışır ancak sınıfın dinamik belleği yönettiğinde sorunlara yol açar.

class Buffer {
    int* data;
    size_t size;
public:
    Buffer(size_t s) : size(s) {
        data = new int[size];
    }
    
    // Derin kopyalama kurucusu
    Buffer(const Buffer& other) : size(other.size) {
        data = new int[size];              // Yeni bellek ayır
        for (size_t i = 0; i < size; i++)
            data[i] = other.data[i];       // İçeriği kopyala
    }
    
    ~Buffer() { delete[] data; }
};

Özel bir kopyalama kurucusu olmadan, her iki nesne de aynı belleği gösterirdi. Biri yok edildiğinde, diğerinin sarkan bir işaretçisi olurdu. Derin kopya, yeni bellek ayırır ve gerçek verileri kopyalayarak her nesnenin kendi kaynaklarına sahip olmasını sağlar.

challenge icon

Görev

Kolay

Sınıfınız dinamik belleği yönetirken derin kopyalamanın önemini gösteren bir mesaj geçmişi sistemi oluşturalım. Mesajları dinamik olarak ayrılmış bir dizide saklayan bir MessageLog sınıfı oluşturacak ve her kopyanın kendine ait bağımsız belleği olmasını sağlamak için uygun bir kopya oluşturucu uygulayacaksınız.

Kodunuzu düzenlemek için iki dosya oluşturacaksınız:

  • MessageLog.h: Dinamik bellek kullanarak bir mesaj koleksiyonunu yöneten bir MessageLog sınıfı tanımlayın. Sınıfınızda şunlar bulunmalıdır:
    • Özel üyeler: Mesajları saklamak için bir dizge dizisine işaretçi, en fazla mesaj sayısını belirten bir capacity ve mevcut mesaj sayısını belirten bir count
    • Bir kapasite alan, diziyi yığında ayıran ve count değerini 0 olarak başlatan parametreli oluşturucu
    • Derin kopyalama yapan bir kopya oluşturucu: Yeni bellek ayıran ve kaynak nesnedeki tüm mesajları kopyalayan
    • Ayrılmış belleği serbest bırakan ve "MessageLog destroyed" yazdıran bir yıkıcı
    • Yer varsa bir mesaj ekleyen bir addMessage(string msg) metodu
    • Mevcut mesaj sayısını döndüren bir getCount() metodu
    • Verilen indeksteki mesajı döndüren bir getMessage(int index) metodu
  • main.cpp: Kopya oluşturucunuzun bağımsız bir kopya oluşturduğunu gösterin. Girdiden bir kapasite değeri ve iki mesaj okuyun, ardından:
    • Girdi kapasitesiyle original adında bir MessageLog oluşturun
    • Her iki mesajı da original'a ekleyin
    • Kopya oluşturucuyu kullanarak backup adında bir kopya oluşturun
    • Üçüncü bir mesajı, "New message", yalnızca original'a ekleyin
    • "Original count: <count>" yazdırın
    • "Backup count: <count>" yazdırın
    • backup'taki tüm mesajları her satıra bir tane gelecek şekilde yazdırın

Girdi biçimi şöyle olacaktır:

  • İlk satır: kapasite (tam sayı)
  • İkinci satır: ilk mesaj (dizge)
  • Üçüncü satır: ikinci mesaj (dizge)

Derin kopyalama doğru uygulanırsa, özgün nesnede 3 mesaj bulunurken yedek kopyada 2 mesaj bulunmalıdır: bu, nesnelerin bağımsız belleğe sahip olduğunu kanıtlar. Uygun bir kopya oluşturucu olmadan ikisi de aynı diziyi paylaşır ve birindeki değişiklikler diğerini etkiler!

Üst bilgi dosyanızı main.cpp dosyasına #include "MessageLog.h" kullanarak ekleyin.

Kendin dene

#include <iostream>
#include <string>
#include "MessageLog.h"
using namespace std;

int main() {
    // Girdiyi oku
    int capacity;
    cin >> capacity;
    cin.ignore();
    
    string msg1, msg2;
    getline(cin, msg1);
    getline(cin, msg2);

    // TODO: Girdi kapasitesiyle 'original' adlı bir MessageLog oluştur

    // TODO: Her iki mesajı da original'a ekle

    // TODO: Kopyalama kurucusunu kullanarak 'backup' adlı bir kopya oluştur

    // TODO: "New message" mesajını yalnızca original'a ekle

    // TODO: "Original count: <count>" metnini yazdır

    // TODO: "Backup count: <count>" metnini yazdır

    // TODO: backup'taki tüm mesajları, her satıra bir mesaj gelecek şekilde yazdır

    return 0;
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online C++ derleyicisi