Warum kann ich das nicht?
class A
{
public:
int a, b;
};
class B : public A
{
B() : A(), a(0), b(0)
{
}
};
amrhassan
Warum kann ich das nicht?
class A
{
public:
int a, b;
};
class B : public A
{
B() : A(), a(0), b(0)
{
}
};
In Silico
Sie können nicht initialisieren a
und b
in B
weil sie keine Mitglieder sind B
. Sie sind Mitglieder von A
also nur A
kann sie initialisieren. Sie können sie öffentlich machen und dann eine Zuweisung vornehmen B
, aber das ist keine empfohlene Option, da es die Kapselung zerstören würde. Erstellen Sie stattdessen einen Konstruktor in A
erlauben B
(oder eine Unterklasse von A
) um sie zu initialisieren:
class A
{
protected:
A(int a, int b) : a(a), b(b) {} // Accessible to derived classes
// Change "protected" to "public" to allow others to instantiate A.
private:
int a, b; // Keep these variables private in A
};
class B : public A
{
public:
B() : A(0, 0) // Calls A's constructor, initializing a and b in A to 0.
{
}
};
Während Ihr Beispiel richtig ist, ist Ihre Erklärung irreführend. Es ist nicht so, dass du es nicht kannst initialisieren a
und b
in B::B()
weil sie privat sind. Sie können sie nicht initialisieren, da sie keine Mitglieder von sind class B
. Wenn Sie sie öffentlich gemacht oder geschützt hätten, könnten Sie das tun zuordnen sie im Körper von B::B()
.
– R. Samuel Klatschko
13. September 2011 um 17:22 Uhr
Darüber hinaus macht Ihre Lösung Klasse A nicht aggregiert, was wichtig sein könnte und daher erwähnt werden muss.
– Gene Buschujew
13. September 2011 um 17:28 Uhr
@R Samuel Klatchko: Guter Punkt. Als ich die Antwort schrieb, tippte ich zunächst “Sie können nicht zugreifen a
und b
…” und änderte es in “Sie können nicht initialisieren …”, ohne sicherzustellen, dass der Rest des Satzes Sinn macht. Beitrag bearbeitet.
– In silico
13. September 2011 um 17:30 Uhr
@Gene Bushuyev: Die Klasse im Originalcode in der Frage ist keine Aggregat (es gibt nicht statische private Mitglieder)
– David Rodríguez – Dribeas
13. September 2011 um 18:04 Uhr
@David – richtig, das ist ein Benutzerfehler, und ich versuche, zu den Absichten des Benutzers zu gelangen, indem ich oberflächlich überspringe.
– Gene Buschujew
13. September 2011 um 18:20 Uhr
NPE
Abgesehen von der Tatsache, dass sie es sind private
seit a
und b
sind Mitglieder von A
sie sollen durch initialisiert werden A
Konstruktoren von , nicht von den Konstruktoren einer anderen Klasse (abgeleitet oder nicht).
Versuchen:
class A
{
int a, b;
protected: // or public:
A(int a, int b): a(a), b(b) {}
};
class B : public A
{
B() : A(0, 0) {}
};
Violette Giraffe
Irgendwie hat niemand den einfachsten Weg aufgelistet:
class A
{
public:
int a, b;
};
class B : public A
{
B()
{
a = 0;
b = 0;
}
};
Sie können nicht auf Basiselemente in der Initialisierungsliste zugreifen, aber der Konstruktor selbst kann wie jede andere Elementmethode darauf zugreifen public
und protected
Mitglieder der Basisklasse.
Hübsch. Gibt es irgendeinen Nachteil dabei?
– Wander3r
9. Januar 2019 um 15:29 Uhr
@SaileshD: Es kann sein, dass Sie ein Objekt mit einem kostspieligen Konstruktor initialisieren. Es wird zuerst standardmäßig initialisiert, wenn die Instanz von B
zugewiesen ist, dann wird es innerhalb der zugewiesen B
Der Konstruktor von . Aber ich denke auch, dass der Compiler das noch optimieren kann.
– Violette Giraffe
10. Januar 2019 um 11:36 Uhr
Innen class A
darauf können wir uns nicht verlassen a
und b
initialisiert wird. Jede Implementierung von class C : public A
könnte beispielsweise vergessen anzurufen a=0;
und gehen a
nicht initialisiert.
– Sparkofska
2. Dezember 2019 um 7:49 Uhr
@Wander3r Ein weiterer Nachteil ist, dass nicht alle Klassen Zuweisungsoperatoren haben. Einige können nur konstruiert, aber nicht zugeordnet werden. Dann bist du fertig…
– Martin Pecka
3. Juni 2020 um 16:09 Uhr
Natürlich Dies ist keine Initialisierung. “Die Unterklassen können sie immer noch neu initialisieren” ist nur Unsinn, C++ hat keine solche Operation wie die Neuinitialisierung.
– Ben Voigt
8. Dezember 2021 um 17:31 Uhr
Mannisch Srivastava
# include<stdio.h>
# include<iostream>
# include<conio.h>
using namespace std;
class Base{
public:
Base(int i, float f, double d): i(i), f(f), d(d)
{
}
virtual void Show()=0;
protected:
int i;
float f;
double d;
};
class Derived: public Base{
public:
Derived(int i, float f, double d): Base( i, f, d)
{
}
void Show()
{
cout<< "int i = "<<i<<endl<<"float f = "<<f<<endl <<"double d = "<<d<<endl;
}
};
int main(){
Base * b = new Derived(10, 1.2, 3.89);
b->Show();
return 0;
}
Dies ist ein funktionierendes Beispiel für den Fall, dass Sie die Datenelemente der Basisklasse initialisieren möchten, die im Objekt der abgeleiteten Klasse vorhanden sind, während Sie diese Werte per Push-Schnittstelle über den Konstruktoraufruf der abgeleiteten Klasse übertragen möchten.
Während dies in seltenen Fällen nützlich ist (wenn das nicht der Fall wäre, hätte die Sprache es direkt erlaubt), werfen Sie einen Blick auf die Basis von Member Idiom. Es ist keine codefreie Lösung, Sie müssten eine zusätzliche Vererbungsebene hinzufügen, aber es erledigt die Arbeit. Um Boilerplate-Code zu vermeiden, könnten Sie verwenden Boost-Implementierung
Warum kannst du es nicht? Weil die Sprache es Ihnen nicht erlaubt, die Mitglieder einer Basisklasse in der Initialisiererliste der abgeleiteten Klasse zu initialisieren.
Wie können Sie dies erreichen? So was:
class A
{
public:
A(int a, int b) : a_(a), b_(b) {};
int a_, b_;
};
class B : public A
{
public:
B() : A(0,0)
{
}
};
Aggregierte Klassen, wie A in Ihrem Beispiel A a {0,0};
, müssen ihre Member öffentlich haben und dürfen keine benutzerdefinierten Konstruktoren haben. Sie werden mit einer Initialisierungsliste initialisiert, z B() : A({0,0}){}
oder in deinem fall
. Die Member der Basisaggregatklasse können im Konstruktor der abgeleiteten Klasse nicht einzeln initialisiert werden. class A
Fragst du warum Sie können das nicht tun, was eine Frage des Sprachdesigns ist, oder fragen Sie wie um diese Sprachbeschränkung zu umgehen?
– Rob Kennedy
13. September 2011 um 17:14 Uhr
Ich dachte, dass es eine Art speziellen Weg gibt, den ich nicht kenne, ohne den Basiskonstruktor verwenden zu müssen.
– amrhassan
13. September 2011 um 20:48 Uhr
Die Member der Basisklasse sind bereits initialisiert, wenn Ihr Konstruktor der abgeleiteten Klasse ausgeführt wird. Du kannst zuordnen sie, wenn Sie Zugriff haben, oder rufen Sie Setter für sie auf, oder Sie können Werte für sie an den Basisklassenkonstruktor liefern, wenn es einen geeigneten gibt. Das einzige, was Sie kann nicht was in der entwickelten Klasse zu tun ist, ist, sie zu initialisieren.
– Benutzer207421
23. August 2017 um 0:25 Uhr