Forum: PC-Programmierung C++ Ableitung und virtual


von Operator S. (smkr)


Lesenswert?

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?

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

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 */ }
22
}

: Bearbeitet durch User
von Jay (Gast)


Lesenswert?

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.

von Operator S. (smkr)


Lesenswert?

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?

von B. S. (bestucki)


Lesenswert?

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:
1
unsigned int X(-123); /* keine Warnung */
2
unsigned int Y{-123}; /* Warnung */

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

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.

Ü

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Operator S. schrieb:
> Torsten R. schrieb:
> Müsste ich hier dann:
>
1
> 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.

von Operator S. (smkr)


Lesenswert?

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.

von A. H. (ah8)


Lesenswert?

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.

von Operator S. (smkr)


Lesenswert?

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 ;-)

von A. H. (ah8)


Lesenswert?

Ach so, init bezieht sich also auf die Hardware und nicht auf die 
Klasse? Na dann habe ich nichts gesagt.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.