Ich steh grad auf dem Schlauch, wie ich mit den Konstruktoren bei
abegleiteten Klassen umgehen muss
1
class A {
2
public:
3
A(string name);
4
virtual void foo() = 0;
5
}
6
7
class B : public A {
8
public:
9
void foo() { /* Algorithmus */ }
10
int getId() { return id; }
11
virtual void init() = 0;
12
13
protected:
14
B(string name, int i);
15
int id;
16
}
17
18
class C : public A {
19
public:
20
C(string name, int i) : id(i) {}
21
void init(){ /* class specific init routine */ }
22
}
Nun bekomme ich die Fehlermeldung, dass Klasse C keinen Member id
enthält. Meine intuition wäre, in der initialisation der Klasse C, den
Constructor B aufzurufen und dort die Werte zu übergeben. Jedoch möchte
ich die Klasse B nicht instanziierbar gestalten, da es keinen Sinn
macht, davon ein Objekt zu erzeugen.
Wie muss ich da vorgehen?
Operator S. schrieb:> Wie muss ich da vorgehen?
Du must die Basisklasse mit in der Intialisierungsliste aufführen und
member dort initialisieren, wo sie auch eingeführt werden (und wenn C
keine id hat, kann die auch nicht initialisiert werden; wahrscheinlich
sollte C von B erben?):
1
class A {
2
public:
3
explicit A(const std::string& name);
4
virtual void foo() = 0;
5
}
6
7
class B : public A {
8
public:
9
void foo() { /* Algorithmus */ }
10
int getId() { return id; }
11
virtual void init() = 0;
12
13
protected:
14
B(const std::string& name, int i) : A( name ), id( i ) {}
15
int id;
16
}
17
18
class C : public A {
19
public:
20
C(const std::string& name, int i) : A( name ) {}
21
void init(){ /* FIXME: class specific init routine */ }
Operator S. schrieb:> Wie muss ich da vorgehen?
Vermutlich ein Schreibfehler. C ist von A abgeleitet. Weder C noch A
enthalten id. Nur B enthält id, davon können aber weder A noch C etwas
wissen.
Torsten R. schrieb:> wahrscheinlich sollte C von B erben?)
Ja, mein Fehler
Torsten R. schrieb:> C(const std::string& name, int i) : A( name ) {}
Müsste ich hier dann:
1
C(const std::string& name, int i) : B( name, i ) {}
aufrufen?
Wie verhindere ich dann, dass B nicht stand-alone als Objekt existieren
kann, wenn es einen Konstruktor hat?
Operator S. schrieb:> virtual void init() = 0;
Sobald eine Klasse eine pure-virtual Funktion hat, ist es eine abstrakte
Klasse. Von solchen Klassen können keine Objekte erzeugt werden. Siehe
auch:
http://www.cplusplus.com/doc/tutorial/polymorphism/
Ich empfehle für Initialisierungen von Objekten geschweifte Klammern zu
verwenden:
Operator S. schrieb:> Nun bekomme ich die Fehlermeldung, dass Klasse C keinen Member id> enthält.
Ich sach mal, der Compiler hat recht.
B ist keine Basisklasse von C. Wenn du das gerne so haben möchtest,
musst du das auch so hinschreiben. Also:
class A
class B: public A
class C: public B
Da B rein virtuelle Funktionen enthält, kannst du die nicht
instanziieren.
Ü
> C(const std::string& name, int i) : B( name, i ) {}
2
>
> aufrufen?
richtig, aber nur, wenn Du den anderen Fehler auch fixed (C erbt von A).
Weder ich, noch der Compiler können richtig raten, was Du in
Wirklichkeit haben möchtest ;-)
> Wie verhindere ich dann, dass B nicht stand-alone als Objekt existieren> kann, wenn es einen Konstruktor hat?
Wenn Du mit stand-alone meinst: B soll nicht instanziierbar sein, dann
passt das mit dem protected c'tor schon ganz gut. Sobald Du einen c'tor
selbst deklarierst, deklariert Dir der compiler keinen default c'tor
mehr. Ausserdem hat B doch noch eine pure virtual function und lässt
sich deshalb auch nicht instanziieren.
Habs gerade ausprobiert, funktioniert. Besten Dank an allen beteiligten.
C erbt natürlich von B, hatte das oben falsch geschrieben.
Mich hat die verschachtelte Konstruktorenaufrufe verwirrt, da
schlussendlich name von C nach B und B nach A weitergegeben wird.
Macht jetzt aber auch Sinn.
Mal ein ganz anderes Problem:
Warum ist Deine init Funktion rein virtuell? Das ist like asking for
trouble. Sei auf jeden Fall darauf vorbereitet, dass der Compiler sich
weigern wird, diese Funktion aus einem Konstruktor der Basisklasse
(z.B. B()) heraus aufzurufen. Das liegt daran, dass die Basisklasse
immer vor der abgeleiteten Klasse initialisiert wird. Eine rein
virtuelle Funktion kann aber erst in einer abgeleiteten Klasse definiert
werden. Ruft der Konstruktor einer Basisklasse eine rein virtuelle
Funktion auf, so ruft er die Funktion einer Instanz, die zu diesem
Zeitpunkt noch gar nicht vollständig initialisiert sein kann, was der
Compiler sinnvollerweise verhindert.
A ist eine generische Klasse, alle meine Klassen im Thread erben davon.
Nun habe ich verschiedene Klassen, die auf die Hardware zugreifen und
initialisiert werden müssen. Ich hatte zuerst bei allen die mehr oder
weniger gleiche Funktion foo() (simple statemachine) implementiert und
gemerkt, dass ich viel duplizierten Code habe.
Um das zu vereinfachen, wollte ich diese Funktion auslagern und hab die
Klasse B erzeugt und dann alle C-Level Klassen von B erben lassen.
Dies ist nur ein vereinfachtes Beispiel, in Realität hat B die
virtuellen Funktionen init(), check() und action(), die für jedes Device
spezifisch sind und in C Klassen implementiert werden.
Dass man virtuelle Funktionen nicht im Konstruktor aufruft habe ich
schon gelernt ;-)