Kopierkonstruktor, wer ruft den auf?
-
Hä, echt? Für was braucht man den dann einen Kopierkonstruktor. Ich hab immer gedacht den nimmt man wenn im Objekt Zeiger vorkommen die Speicher auf dem Heap reserviert haben. Sodass dann nicht bei zwei Objekten die Adressen gleich sind auf die die Zeiger zeigen. Sonst gibts doch irgendwie nen Crash?
-
kommt drauf an:
Haus haus2 = haus1; // entspricht: Haus haus2(haus1) --> CpyCtor wird aufgerufen. (von haus2) Haus haus3; haus3 = haus1; // operator= wird aufgerufen. (von haus3)
-
Ja, Stromberg du hast net Unrecht -
aber wenn du den Kopierkonstruktor überladen musst, dann musst du in der Regel auch den ZUweisungsoperator und den Destruktor überladen ...dafür braucht man den Kopierkonstruktor:
TObject Object1; // do something TObject Object2(Object1);
-
Also...
a) Die Rechte Seite eines Ausdrucks wird auf die Linke angewendet. Daher würde es wenn Haus2 sein...
b) Der Kopierkonstruktor wird nur bei der Initialisierung aufgerufen, der Zuweisungsoperator immer wenn nach einer Initialisierung eine Zuweisung erfolgt.
Beispiel:
class Haus { ... }; int main() { Haus haus1; Haus haus2 = haus1; // Initialisierung, daher Kopierkonstruktor (von haus2) Haus haus3(haus1); // Ebenso (nur halt von haus3) haus2 = haus1; // Nachträgliche Zuweisung: Zuweisungsoperator return 0; }cu André
-
Also wenn ich das richtig verstanden habe, dann wird der Kopierkonstruktor nur dann aufgerufen wenn die zuweisung gleich währen der initialisierung stattfindet? Also (wie schon von asc gesagt):
Haus haus2 = haus1; //tiefe Kopieund wenn man es aber einfach so irgendwann mancht und nicht während der Initialisierung, dann findet nur eine flache Kopie statt, und man muss den operator "=" überladen und ihm sagen das er den Kopierkonstruktor aufrufen soll?
haus2 = haus1; //flache KopieDankeschön schon mal im Voraus.
-
Nein.
Der Konstruktor konstruiert Objekte.
Haus a;
hier wird a konstruiert.
a=b;
a ist schon konstruiert, es erfolgt eine einfache Zuweisung ohne irgendwelche Konstruktoren. Den Zuweisungsoperator musst du trotzdem überladen und ihm sagen was er tun soll. Aber mit einem Konstruktor hat das nichts zu tun. Konstruktoren erstellen neue Objekte. a existiert aber definitiv schon.
-
Kopierkonstruktor. Ich hab immer gedacht den nimmt man wenn im Objekt Zeiger vorkommen die Speicher auf dem Heap reserviert haben
nein.
der CpyCtor macht eigentlich das gleiche wie der operator= (normalerweise).Unterschied: Falls Zeiger im Objekt vorkommen muss man beim CpyCtor nicht überprüfen worauf die Zeiger zeigen, bevor man (dem Zeigerwert selbst) neue Werte zuweist.
Wenn man beim operator= nicht überprüft worauf die Zeiger zeigen und einfach einen neuen wert zuweist, können speicherlöcher entstehen (falls die Adresse, des Objektes auf das der Zeiger gezeigt hat nicht einem anderen Objekt bekannt ist).dann steht in dem oben geposteten link:
Haus( Haus const& rhs ) { *p1 = rhs.Get_p1(); // p1 u p2 sind Zeiger *p2 = rhs.Get_p2(); ... }Das würde ich lassen.
p1 etc. zeigen irgendwo in den speicher,
mit *p1 greifst du also auf speicher zu, der dir nicht gehört.evtl meinst du:
class Haus { private: HausElement *p1; Haus( Haus const& rhs ) { p1 = rhs.Get_p1(); // also: p1 = rhs.p1; } // oder Haus( Haus const& rhs ) { p1 = new HausElement(); *p1 = rhs.Get_p1(); // also: *p1 = *(rhs.p1); } // dann wäre es aber wahrs. güstiger das HausElement gleich ins Haus zu setzen // also: HausElement he1; statt: HausElement *p1; }
-
wandrer schrieb:
....mit *p1 greifst du also auf speicher zu, der dir nicht gehört.
Ich hab mir im Konstruktor aber zuvor speicher reserviert:
Haus::Haus(int a,int b,int c) { p1=new int(a); p2=new int(b); p3=new int(c); }Also wenn du das meinst? Aber so wärs doch dann in Ordnung oder?
-
Hier mal noch n ähnlicher vollständiger Code:
#include <iostream> using namespace std; class Mammal { public: Mammal(int a,int b,int c); Mammal(const Mammal &rhs); ~Mammal(); int Get_p1() const {return *p1;} int Get_p2() const {return *p2;} int Get_p3() const {return *p3;} private: int *p1; int *p2; int *p3; }; Mammal::Mammal(int a,int b,int c) { p1=new int(a); p2=new int(b); p3=new int(c); } Mammal::Mammal(const Mammal &rhs) { *p1=rhs.Get_p1(); *p2=rhs.Get_p2(); *p3=rhs.Get_p3(); } Mammal::~Mammal() { } class Dog : public Mammal { public: Dog(int LA_a,int LA_b,int LA_c,int a,int b,int c); Dog(const Dog &rhs); ~Dog(); int Get_p1() const {return *p1;} int Get_p2() const {return *p2;} int Get_p3() const {return *p3;} private: int *p1; int *p2; int *p3; }; Dog::Dog(int LA_a,int LA_b,int LA_c,int a,int b,int c) :Mammal(LA_a,LA_b,LA_c) { p1=new int(a); p2=new int(b); p3=new int(c); } Dog::Dog(const Dog &rhs) :Mammal(rhs) { *p1=rhs.Get_p1(); *p2=rhs.Get_p2(); *p3=rhs.Get_p3(); } Dog::~Dog() { } int main() { return 0; }So wär das aber doch ganz sauber gemacht oder?
Dankeschön schon mal im Voraus.
EDIT: Das deleten in den Desturktoren hab ich jetzt halt vergessen.
-
Nein.
Dein Konstruktor ist ok. Aber dein Kopierkonstruktor schreibt in Speicher der dir nicht gehört. p1, p2 und p3 haben keinen Speicher zugewiesen bekommen.Das Löschen im Destruktor fehlt und der Zuweisungsoperator fehlt.
Nochmal:
die Konstruktoren erstellen etwas: der Kopierkonstruktor erstellt das Objekt. Es wird nicht zuerst der Standard Konstruktor aufgerufen sondern sofort der Kopierkonstruktor.Und du hast ein Namensproblem: warum nennst du alle Attribute und Methoden gleich? Du solltest da schon etwas differenzieren. p1 in Dog ist ein anderes p1 als in Mammal. Da solltest du eigentlich eine Compilerwarnung bekommen.
-
Du kannst aber die ints auch "direkt" verwenden, also so:
class Mammal { public: Mammal(int a,int b,int c); Mammal(const Mammal &rhs); ~Mammal(); int Get_p1() const {return p1;} int Get_p2() const {return p2;} int Get_p3() const {return p3;} private: int p1, p2, p3; }; Mammal::Mammal(int a,int b,int c) { p1=a; p2=b; p3=c; } Mammal::Mammal(const Mammal &rhs) { p1=rhs.Get_p1(); p2=rhs.Get_p2(); p3=rhs.Get_p3(); } Mammal::~Mammal() { // Den brauchst du dann eigentlich nicht mehr }
-
@Badestrand
Ja aber ich hab hier halt absichtlich Zeiger genommen, weil es ja um den Kopierkonstruktor ging, wenn keine Zeiger dabei sind braucht man den Kopierkonstruktor ja eigentlich net.@Shade Of Mine
Hier wird also sofort der Kopierkonstruktor aufgerufen? :Haus haus2(haus1);Ach so, und deshlab muss ich mir den Speicher dann auch nochmal im Kopierkonstruktor reservieren, weil wenn der normale Konstruktor ja nicht mehr aufgerufen wird dann wird auch kein Speicher mehr reserviert..?
*Ah ich glaub mir ist ein Licht auf gegangen*Dankeschön schon mal im Voraus.
-
Wie is der Code jetzt, schaut der sauber aus? :
#include <iostream> using namespace std; class Mammal { public: Mammal(int a,int b,int c); Mammal(const Mammal &rhs); virtual ~Mammal(); int Get_p1() const {return *p1;} int Get_p2() const {return *p2;} int Get_p3() const {return *p3;} private: int *p1,*p2,*p3; }; Mammal::Mammal(int a,int b,int c) { p1=new int(a); p2=new int(b); p3=new int(c); } Mammal::Mammal(const Mammal &rhs) { p1=new int(rhs.Get_p1()); p2=new int(rhs.Get_p2()); p3=new int(rhs.Get_p3()); } Mammal::~Mammal() { delete p1; delete p2; delete p3; } class Dog : public Mammal { public: Dog(int LA_a,int LA_b,int LA_c,int a,int b,int c); Dog(const Dog &rhs); ~Dog(); int Get_m1() const {return *m1;} int Get_m2() const {return *m2;} int Get_m3() const {return *m3;} private: int *m1,*m2,*m3; }; Dog::Dog(int LA_a,int LA_b,int LA_c,int a,int b,int c) :Mammal(LA_a,LA_b,LA_c) { m1=new int(a); m2=new int(b); m3=new int(c); } Dog::Dog(const Dog &rhs) :Mammal(rhs) { m1=new int(rhs.Get_m1()); m2=new int(rhs.Get_m2()); m3=new int(rhs.Get_m3()); } Dog::~Dog() { delete m1; delete m2; delete m3; } int main() { return 0; }Dankeschön schon mal im Voraus.
-
Erstens: Für einzelne int-Werte brauchst du keine Zeiger.
Zweitens: Beide Klassen benötigen noch einen operator=, sonst fliegt dir das Programm rechnt schnell um die Ohren (die Standardversion macht eine flache Kopie aller Member, d.h. nach einer Zuweisung m2=m1 arbeiten beide mammal's mit den selben Daten (und die int's, die m1 im Ctor geholt hat, bleiben unerreichbar im Speicher zurück).
-
CStoll schrieb:
Erstens: Für einzelne int-Werte brauchst du keine Zeiger....
Stromberg schrieb:
@Badestrand
Ja aber ich hab hier halt absichtlich Zeiger genommen, weil es ja um den Kopierkonstruktor ging, wenn keine Zeiger dabei sind braucht man den Kopierkonstruktor ja eigentlich net.:p
