Fragen zu Copy Konstruktor
-
[Das ganze würde auch ohne eigenen Copy Konstruktor funktionieren, aber darum geht es hier nicht...]
In der folgenden Beispielklasse habe ich folgende Zuweisung im Copy Konstruktor:
RectShape(const RectShape & s) { m_width = s.width(); m_height = s.height(); }Warum müssen dafür die Funktionen width() const sein? Sind sie es nicht bekomme ich den Fehler:
1> error C2662: 'RectShape::width': this-Zeiger kann nicht von 'const RectShape' in 'RectShape &' konvertiert werden
1> Durch die Konvertierung gehen Qualifizierer verlorenWenn ich die Zuweisung ändere zu
RectShape(const RectShape & s) { this->m_width = s.m_width; this->m_height = s.m_height; }dann greife ich direkt auf private Member zu. Warum geht das hier?
Die ganze Klasse ist zudem von einer weiteren Klasse abgeleitet (AbstractShape).
Wie kopiere ich diese im Copy Konstruktor?class RectShape : public AbstractShape { public: RectShape(void) : AbstractShape(), m_width(0), m_height(0) { setDescription("Rectangular Shape"); } RectShape(const RectShape & s) { m_width = s.width(); m_height = s.height(); } const RectShape& operator=(const RectShape& rhs) { if (this != &rhs) { this->m_width = rhs.m_width; this->m_height = rhs.m_height; } return *this; } ~RectShape(void); void setSize(double width, double height) { setWidth(width); setHeight(height); } void setWidth(double width) { assert(width > 0); m_width = width; } void setHeight(double height) { assert(height > 0); m_height = height; } double width() const { return m_width; } double height() const { return m_height; } double area () const { return (m_width * m_height); } private: double m_width; double m_height; };
-
Weil du da ein konstantes Objekt hast und die Funktionen müssen daher auch konstant sein. Wenn du direkt auf die Member zugreifst, dann sind die schon (durch das Schlüsselwort für das Objetk) konstant.
EDIT:
Kannst ja mal probieren s.m_width etwas zuzuweisen im ctor.
-
pospiech schrieb:
...Warum müssen dafür die Funktionen width() const sein?...
weil:
pospiech schrieb:
...
RectShape(const <<<----...

hat übrigens nicht zentral mit "Copy-Konstruktor" zu tun sondern ist mit auch jeder Funktion so....
Gruß,
Simon2.
-
Ok, das mit den const Funktionen habe ich begriffen (ist auch logisch wenn man darüber nachdenkt), aber zu meinen weiteren beiden Fragen:
- warum kann ich auf private Member zugreifen
- wie kopiere ich eine abgeleitete Klasse?
-
pospiech schrieb:
Ok, das mit den const Funktionen habe ich begriffen (ist auch logisch wenn man darüber nachdenkt), aber zu meinen weiteren beiden Fragen:
- warum kann ich auf private Member zugreifen
- wie kopiere ich eine abgeleitete Klasse?1.) Warum solltest du nicht auf die privaten Member zugreifen können?Dafür ist doch der Ctor bzw CopyCtor zuständig.
2.) Wenn ich nach den Benennungen der Klassen in deinem Beispiel gehe, und mir der NameAbstractShapeins Auge fällt, frage ich mich ob du wirklich verstanden hast was du da machst.Weil warum solltest du diese Klasse in deinem CopyCtor deiner konkreten Klasse kopieren wollen, mal davon abgesehen wüsste ich nicht mal ob das der Standard überhaupt zulässt so wie du dir das vorstellst.
-
pospiech schrieb:
- warum kann ich auf private Member zugreifen
Häufiges Verständnisproblem: Du darfst innerhalb einer Klasse auf alle privaten Member dieser Klasse zugreifen, nicht nur auf die des this-Objekts.
-
pospiech schrieb:
- wie kopiere ich eine abgeleitete Klasse?
In dem du z.B. den Basisinitialisierer deiner Klasse aufrufst (Copy-Konstruktor bleibt ja immer noch ein Konstruktor).
RectShape(const RectShape& other) : AbstractShape(other)Sollte gehen, denn RectShape ist ja auch ein AbstractShape. Brauchst halt einen CopyCTor für AbstractShape.
Wenn du aber vorhast, auch das Kopieren von Basisklassen in eine abgeleitete Klasse zulässt, bietet sich so etwas an
RectShape(const AbstractShape& other)
-
pospiech schrieb:
...
Ein paar ergänzende Anmerkungen:
1. Sei dir mal das Thema Const-Correctness ans Herz gelegt, auch wenn du inzwischen wohl einen Teil verstanden hast.
2. In einer Instanz einer Klasse hast du Zugriff auf alle Member dieser Instanz, und aller anderen - bekannten - Instanzen dieser Klasse. Sprich: Wenn du innerhalb einer Methode einer RectShape-Instanz eine andere RectShape-Instanz übergeben bekommst, hast du auch auf diese den vollen Zugriff (von const mal abgesehen).
3. Die Initialisierungsliste ist dem Konstruktorrumpf vorzuziehen.
RectShape(const RectShape & s) // <-- Hier werden die Member initialisiert { this->m_width = s.m_width; // Und hier erfolgt eine nachträgliche Zuweisung this->m_height = s.m_height; } // Besser: RectShape(const RectShape & s) : m_width(s.m_width), m_height(s.m_height) { }Was ist nun der genaue Unterschied? Nehmen wir mal an das deine Member Objekte einer Klasse sind:
Im ersten Fall mussen die Klassen der Membervariablen einen Standardkonstruktor und einen Zuweisungsoperator haben. Beide werden Aufgerufen (Es erfolgt eine Initialisierung und anschließende Zuweisung).
Im zweiten Fall wird direkt der entsprechende Konstruktor der Membervariable aufgerufen, es erfolgt nur dieser Konstruktoraufruf.
Zudem kannst du innerhalb der Initialisierungsliste auch Konstanten und Referenzen initialisieren, was im Konstruktorrumpf nicht geht. Zudem kann man hier bei Vererbung einen speziellen Konstruktor der Basisklasse aufrufen (Statt dem Standardkonstruktor).
Das einzige was man dabei Beachten muss ist, das die Initialisierungsliste in der Reihenfolge initialisiert, wie die Member in der Klasse deklariert wurden, und nicht in der Reihenfolge wie du sie in der Initialisierungsliste aufführst (Wichtig bei voneinander abhängigen Initialisierungen). Am leichtesten ist daher: Immer die Initialisierungsliste in der Reihenfolge wie die Memberdeklaration schreiben.
3. Im Falle einer Ableitung wird im Konstruktor der abgeleiteten Klasse implizit auch der Kopierkonstruktor der Basisklasse aufgerufen (Die Initialisierung beginnt immer mit der untersten Basisklasse). Du musst dich daher nur um die Initialisierung/Kopie der Klasseneigenen Member kümmern.
cu André