2016-06-23 18 views
1

Ich habe eine Klasse B mit einem Member, der ein Zeiger auf ein Objekt einer Klasse A ist. Wenn Sie den Kopierkonstruktor für ein Objekt vom Typ A verwenden, wird es kopiert, die Elementvariable jedoch nicht. Gibt es eine Möglichkeit, ein A-Objekt zu kopieren und automatisch eine Kopie seines B-Mitglieds zu erstellen? Der folgende Code zeigt das Problem, das ich bin triying zu erklären:Erstellen einer Kopie eines beliebigen Zeigerelements im Kopierkonstruktor varible

class A 
{ 
public: 
    A(char t_name) 
    { 
     name = t_name; 
    } 
    ~A() 
    { 
    } 
    char name; 
}; 

class B 
{ 
public: 
    A* attribute; 

    B() 
    { 
     attribute = new A('1'); 
    } 
    ~B() 
    {} 
}; 


int main() 
{ 
    B* b_variable = new B; 
    B* b_copy = new B(*b_variable); 
    return 0; 
} 
+0

Schreiben Sie den Kopierkonstruktor, operator = und reparieren Sie Ihren Destruktor der Klasse B.Siehe Beiträge auf der Regel von 3 und/oder 5. http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three http://stackoverflow.com/questions/4782757/rule-of -three-wird-rule-of-five-with-c11 –

+1

Warum ändert Ihr Code die Bedeutung von 'A' und' B' in Ihrer * Beschreibung *? Es ist "B", dass ein Mitglied auf ein "A" zeigt. –

+1

@Alex Warum würdest du überhaupt einen Hinweis auf etwas in der heutigen Zeit behalten? Warum nicht einfach ein 'A'-Mitglied behalten und dann sind alle deine Probleme gelöst. –

Antwort

1

Wenn auf einem Objekt vom Typ A Kopie Konstruktor, es kopiert wird, aber die Membervariable nicht.

Ihr Code ruft nie Copykonstruktor in der Klasse A.

Ihr Code ruft eine Kopie Konstruktor in der Klasse B und es tut genau das, was soll, wird der Wert von attribute dh Kopien, die ein ist Zeiger auf ein Objekt der Klasse A.

Mit anderen Worten - nach der Ausführung Ihres Codes haben Sie zwei Instanzen der Klasse B und eine Klasse A-Instanz. In den beiden Instanzen der Klasse B zeigt attribute auf dieselbe Klasse-A-Instanz.

Dies ist (wahrscheinlich) nicht das, was Sie wollen.

Wie bereits erwähnt (z. B. @ lostbard-Antwort), benötigen Sie einen Kopierkonstruktor in Klasse B, um eine Deep-Copy zu erstellen. Eine tiefe Kopie wird benötigt, weil Klasse B ein Zeigerelement hat.

Auch sollten Sie einige Aufräumarbeiten in Klasse B Destruktor und in Haupt tun.

#include <iostream> 
using namespace std; 

class A 
{ 
public: 
    A(char t_name) 
    { 
     name = t_name; 
    } 

    ~A() 
    { 
    } 
    char name; 
}; 

class B 
{ 
public: 
    A* attribute; 

    B() 
    { 
     attribute = new A('1'); 
    } 

    /** Copy constructor */ 
    B(const B &copy) 
    { 
     // Make a new instance of class A 
     attribute = new A(*copy.attribute); 
    } 

    /** Assignment operator */ 
    B& operator= (const B& other) 
    { 
     // Delete the existing class A instance 
     delete attribute; 
     // and create a new as a copy of other.attribute 
     attribute = new A(*other.attribute); 
    } 

    ~B() 
    { 
     // Delete the class A instance 
     delete attribute; 
    } 
}; 


int main() 
{ 
    B* b_variable = new B; 
    B* b_copy = new B(*b_variable); 

    // Delete the two class B instances 
    delete b_variable; 
    delete b_copy; 

    return 0; 
} 

Es ist kein Kopierkonstruktor in Klasse A erforderlich. Der standardmäßig generierte Standard funktioniert, da Klasse A keine Zeigerelemente hat.

EDIT

Wie bereits von @Slava out Sie sollten immer einen Zuweisungsoperator implementieren, wenn Sie eine Kopie Konstruktor (Regel drei) machen, so fügte ich es oben auf den Code.

Einige mögen die Regel von drei, um die Regel von fünf zu sein, also schließt sie auch Bewegung ein. Lesen Sie hier mehr: https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)

+0

fehlt Ihnen noch der Zuweisungsoperator – Slava

+0

@Slava - rechts, hinzugefügt ... – 4386427

+0

Warum 'A * attribut;' und nicht 'A attribute'? – lorro

0

Zwar gibt es viele Lösungen gibt, ich tippe eher or später werden Sie mit der Umsetzung der üblichen virtuellen a.clone(); enden. Das funktioniert einwandfrei, wenn Sie Klassen von A abgeleitet haben (was mehr oder weniger der einzige legitime Grund ist, warum Sie A als Zeiger auf ein dem Heap zugewiesenes Objekt und nicht als Value-Member behalten).

Beachten Sie, dass C++ bei der Implementierung von clone() in Ihrer Hierarchie Rückgabetypen für kovariante Zeiger unterstützt. Wenn also die Basis eine virtuelle hat, die z. Clonable*, dann A 's gleiche Methode kann A* zurückgeben und A's Nachfahren ADerived kann ADerived* zurückgeben. Fühlen Sie sich frei zu verstehen, "kann" als "sollte" für den Fall clone().

+0

Denk, du bist hier auf dem falschen Weg. Wenn dies eine Frage der Vererbung ist, kann "clone" nützlich sein. Da dies jedoch eine contains-Beziehung ist, ist der Kopierkonstruktor bei weitem die bessere Option. 'clone' macht keine Klasse Rule of Three-konform. – user4581301

+0

Ich sage nicht, dass OP es gerade braucht, ich sage früher oder später, dass wir damit enden werden. Warum hätten wir dann nicht einfach 'A attribute;' statt 'A *'? Die Klasse weist A selbst zu, so dass der Pool von A-Objekten wahrscheinlich nicht der Grund ist. Was die Dreiregel betrifft, bin ich auch nicht konform: Ich neige dazu, konstant korrekte Klassen zu bilden, wo die Zuordnung keine gültige Bedeutung hat. Vielleicht sollten wir diese Regel nicht strikt befolgen, sondern eher als Hinweis. – lorro

0

eine Kopie Konstruktor für A erstellen und für B:

class A 
{ 
public: 
    A(char t_name) 
    { 
    name = t_name; 
    } 
    A(const A& copy) 
    { 
     name = copy.name; 
    } 
    ~A() 
    { 
    } 
    char name; 
}; 

class B 
{ 
public: 
    A* attribute; 

    B() 
    { 
     attribute = new A('1'); 
    } 
    B(const B &copy) 
    { 
     attribute = new A(*copy.attribute); 
    } 
    ~B() 
    {} 
}; 
+1

Es ist nicht notwendig, eine Kopie ctor für 'A' – Slava

+0

zu erstellen, es ist in diesem Fall nicht erforderlich, da das Feld nur ein Zeichen ist, aber wenn es ein komplexeres Problem ist, könnte es erforderlich werden. – lostbard

+0

Es ist so schön, sich um einen hypothetischen Fall zu kümmern, vor allem, wenn Sie sich nicht um Speicherlecks in dtor und fehlenden Zuweisungsoperatoren gekümmert haben. – Slava