C++ Ableitung und virtual

OP #4647906
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?
(Firma: Torrox.de) #4647919
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
}
#4647936
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 */
(Firma: Torrox.de) #4647943
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.
OP #4647950
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.
#4647972
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.
OP #4647997
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 ;-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren