Kopya Yapıcı
Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 20 / 104.
Kopya oluşturucu, mevcut bir nesnenin kopyası olarak yeni bir nesne oluşturur. Bir nesneyi aynı türdeki başka bir nesneden başlattığınızda, bir nesneyi değere göre geçirdiğinizde veya bir nesneyi değere göre döndürdüğünüzde çağrılır.
Kopya oluşturucu, aynı sınıftaki bir nesneye const referans alır:
class Player {
std::string name;
int health;
public:
Player(std::string n, int h) : name(n), health(h) {}
// Kopya yapıcı
Player(const Player& other) {
name = other.name;
health = other.health;
}
};
Player original("Hero", 100);
Player copy = original; // Kopya yapıcı çağrıldı
Player another(original); // Ayrıca kopya yapıcıyı çağırırBir kopya oluşturucu tanımlamazsanız, derleyici sığ kopyalama işlemi gerçekleştiren bir kopya oluşturucu üretir - her üyenin değerini doğrudan kopyalar. Bu, basit türler için sorunsuz çalışır, ancak sınıfınız 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 kopya 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]; // İçerikleri kopyala
}
~Buffer() { delete[] data; }
};Özel bir kopya oluşturucu olmadan, her iki nesne de aynı belleği gösterirdi. Biri yok edildiğinde, diğerinde geçersiz bir işaretçi kalırdı. Derin kopya yeni bellek ayırır ve gerçek verileri kopyalar; böylece her nesnenin kendi kaynaklarına sahip olması sağlanır.
Görev
KolaySınıfınız dinamik belleği yönettiğinde derin kopyalamanın önemini gösteren bir mesaj geçmişi sistemi oluşturalım. Mesajları dinamik olarak ayrılmış bir dizide depolayan bir MessageLog sınıfı oluşturacak ve her kopyanın kendine ait bağımsız belleğe sahip 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 birMessageLogsınıfı tanımlayın. Sınıfınız şunlara sahip olmalıdır:- Özel üyeler: mesajları depolamak için bir string dizisine işaretçi, maksimum mesaj sayısı için bir
capacityve mevcut mesaj sayısı için bircount - Bir kapasite alan, diziyi heap üzerinde ayıran ve count değerini 0 olarak başlatan parametreli oluşturucu
- Yeni bellek ayırıp kaynak nesnedeki tüm mesajları kopyalayan bir derin kopya gerçekleştiren kopya oluşturucu
- Ayrılan belleği serbest bırakan ve
"MessageLog destroyed"yazdıran bir yıkıcı - Yer varsa bir mesaj ekleyen
addMessage(string msg)yöntemi - Mevcut mesaj sayısını döndüren bir
getCount()yöntemi - Belirtilen dizindeki mesajı döndüren bir
getMessage(int index)yöntemi
- Özel üyeler: mesajları depolamak için bir string dizisine işaretçi, maksimum mesaj sayısı için bir
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
MessageLogadlı biroriginaloluşturun - Her iki mesajı da
originalnesnesine ekleyin - Kopya oluşturucuyu kullanarak
backupadlı bir kopya oluşturun - Yalnızca
"New message"nesnesine üçüncü bir mesaj olanoriginalekleyin "Original count: <count>"yazdırın"Backup count: <count>"yazdırınbackupiçindeki tüm mesajları satır başına bir tane olacak şekilde yazdırın
- Girdi kapasitesiyle
Girdi biçimi şöyle olacaktır:
- İlk satır: kapasite (tam sayı)
- İkinci satır: ilk mesaj (string)
- Üçüncü satır: ikinci mesaj (string)
Derin kopyanız doğru şekilde uygulanırsa, yedek 2 mesaja, original ise 3 mesaja sahip olmalıdır: bu, bağımsız belleğe sahip olduklarını kanıtlar. Uygun bir kopya oluşturucu olmadan her ikisi de aynı diziyi paylaşır ve birindeki değişiklikler diğerini etkiler!
Başlık dosyanızı #include "MessageLog.h" kullanarak main.cpp dosyasına dahil edin.
Kendin dene
#include <iostream>
#include <string>
#include "MessageLog.h"
using namespace std;
int main() {
// Girişi oku
int capacity;
cin >> capacity;
cin.ignore();
string msg1, msg2;
getline(cin, msg1);
getline(cin, msg2);
// TODO: Giriş kapasitesiyle 'original' adında bir MessageLog oluştur
// TODO: Her iki mesajı da original'e ekle
// TODO: Kopya yapıcıyı kullanarak 'backup' adında bir kopya oluştur
// TODO: Yalnızca original'e "New message" ekle
// TODO: Print "Original count: <count>"
// TODO: "Backup count: <count>" yazdır
// TODO: backup'taki tüm mesajları, her satıra bir tane olacak şekilde yazdır
return 0;
}
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
1OOP Temelleri
Harici DosyalarC++ Build ve DerlemeBaşlık Dosyaları ve Kaynak DosyalarıAd Alanları ve KapsamC++'ta OOP'ye GirişSınıflar ve Nesneler'this' İşaretçisiMetotlar (Üye Fonksiyonlar)Öznitelikler (Veri Üyeleri)Ctor ve Dtor TemelleriÖzet - Basit Hesap Makinesi4Sınıf Özellikleri
Örnek ve Statik ÜyelerGetter ve Setter MetotlarıConst Üye FonksiyonlarMutable Anahtar KelimesiStatik Metotlar ve DeğişkenlerFriend Fonksiyonlar ve SınıflarÖzet - Banka Hesabı Yöneticisi7Kalıtım
Temel KalıtımKalıtım Erişim SeviyeleriCtor ve Dtor Çağrılma SırasıMetot Geçersiz KılmaSanal Fonksiyonlar ve VTableÇoklu KalıtımSanal KalıtımÖzet - Çalışan Hiyerarşisi10STL Genel Bakış
STL Genel Bakış ve FelsefesiSTL KonteynerleriİteratörlerSTL AlgoritmalarıFunctor'lar ve Lambda İfadeleriÖzet - Kelime Frekansı13Tasarım Kalıpları 1. Bölüm
Tasarım Kalıplarına GirişSingleton KalıbıFactory ve Abstract FactoryBuilder KalıbıObserver KalıbıStrategy Kalıbı2Bellek Yönetimi
Stack ve Heap Bellekİşaretçiler ve ReferanslarDinamik Bellek (new/delete)C++'ta Akıllı İşaretçilerC++'ta RAIIÖzet - Dinamik Dizi Yöneticisi5Kapsülleme
C++'da Erişim BelirleyicilerDerinlemesine Erişim BelirleyicilerBilgi GizlemeStruct vs Classİç İçe ve Dahili SınıflarÖzet - Öğrenci Kayıt Sistemi8Çok Biçimlilik
Derleme ve Çalışma Zamanı Çok BiçimliliğiFonksiyon Aşırı YüklemeSanal Fonksiyonlara Yeniden BakışSaf Sanal FonksiyonlarSoyut SınıflarC++'ta Arayüz TasarımıDynamic Casting ve RTTIÖzet - Şekil Hesaplayıcı3Yapıcılar ve Yıkıcılar
Varsayılan YapıcıParametreli YapıcıKopya YapıcıTaşıma YapıcısıYapıcı İlklendirme ListeleriTemsilci YapıcılarYıkıcılara Derinlemesine BakışÜç / Beş / Sıfır KuralıÖzet - String Sınıfı6Operatör Aşırı Yükleme
Operatör Aşırı Yüklemeye GirişAritmetik Operatör Aşırı YüklemeKarşılaştırma Operatörü Aşırı YüklemeStream OperatörleriAtama Operatörü Aşırı Yükleme[] ve () Operatör Aşırı YüklemeTip Dönüşüm OperatörleriÖzet - Matris Sınıfı9Şablonlar
Fonksiyon ŞablonlarıSınıf ŞablonlarıŞablon ÖzelleştirmeVariadic ŞablonlarSFINAE ve Type Traits TemelleriÖzet - Generic KonteynerKendi başına pratik yap: Online C++ derleyicisi