Nochmal Vererbung
-
Da ich noch immer einige Probleme damit habe:
Ich habe Klasse Basis und Derived,
ich möchte dass immer wenn ein von Basis abgeleitetes Objekt erstellt wird, ein Counter erhöht wird:class Basis { public: static int COUNTER; int id; Basis(): id(COUNTER){ Basis::COUNTER ++}; }Wenn nun die Klasse Derived einen Konstruktor ohne Argumente erhält, was passiert?
class Derived: public Basis { Derived(){}; }wird dann bei der erstellung eines derived der Konstruktor von Basis aufgerufen, weil die Argumente übereinstimmen (Konstruktoren werden doch eigentlich nicht mitvererbt) ?
Falls das der Fall ist, was würde bei "widersprüchlichen" Konstruktoren der Fall sein?
class Derived : public Basis { Derived(): id(42){}; }Würde dann der "alte" Konstruktor überdeckt?
Annahme Basis würde so aussehen:
class Basis { int id; Basis(int x): id(x); }Könnte eine Klasse Derived die so aussieht:
class Derived: public Basis { }überhaupt erstellt werden? Sie dürfte ja keinen gültigen Konstruktor mehr haben, oder?
So ich hoffe ich habe jetzt alle Fälle abgedeckt^^
-
shisha schrieb:
Wenn nun die Klasse Derived einen Konstruktor ohne Argumente erhält, was passiert?
wird dann bei der erstellung eines derived der Konstruktor von Basis aufgerufen, weil die Argumente übereinstimmen (Konstruktoren werden doch eigentlich nicht mitvererbt) ?Nein, Konstruktoren werden nicht vererbt. Aber wenn du eine Instanz von Derived erstellst, wird zuerst der Basis-Teil konstruiert und demnach auch dessen Konstruktor aufgerufen. Das ist immer der Standardkonstruktor, es sei denn, du gibst etwas anderes an (siehe unten).
shisha schrieb:
Falls das der Fall ist, was würde bei "widersprüchlichen" Konstruktoren der Fall sein?
Würde dann der "alte" Konstruktor überdeckt?Nö, probier es aus: das kompiliert nicht. Nur die Basisklasse darf id initialisieren, denn wenn der Derivedkonstruktor an die Reihe kommt, müssen alle Elemente von Basis schon fertig konstruiert und initialisiert sein.
shisha schrieb:
Annahme Basis würde so aussehen:
...
überhaupt erstellt werden? Sie dürfte ja keinen gültigen Konstruktor mehr haben, oder?Doch, das geht, indem du explizit angibst, welcher Basisklassenkonstruktor verwendet werden soll:
class Derived: public Basis { public: Derived() : Basis(42) {} };
-
Athar schrieb:
Nö, probier es aus: das kompiliert nicht. Nur die Basisklasse darf id initialisieren, denn wenn der Derivedkonstruktor an die Reihe kommt, müssen alle Elemente von Basis schon fertig konstruiert und initialisiert sein.
Was ist nun wenn ich etwas habe wie
class Basis { int typ; }Jedes von Basis abgeleitete Objekt soll einen Typ haben um Unterklassen zu unterscheiden,
Beispiel Derived1 soll immer typ=1 haben Derived2 immer typ=2 ...
In diesem Fall kann der Typ aber nicht schon im Konstruktor von Basis festgelegt werden, da ja erst die abgeleiteten Klassen ihre Typ-Zahl kennen werden.Was kann man da tun?
-
Du kannst im Derivedkonstruktor durchaus typ=1; schreiben, nur darfst du die Initialisierungsliste dafür nicht benutzen.
Eine ganz andere Lösung wäre auch eine virtuelle Methode getType().
-
wo würde man diese Funktion dann sinnvollerweise ausführen?
bzw kannst du das etwas erläutern?ich möcht auf keinen fall irgendwas wie type(pointer)== type(pointer2)
verwenden müssen^^
-
Ich meinte sowas:
enum EObjectType {OT_UNKNOWN,OT_DERIVED,OT_ANOTHER_DERIVED}; struct Base { virtual EObjectType getType() {return OT_UNKNOWN;} }; struct Derived : public Base { virtual EObjectType getType() {return OT_DERIVED;} }; struct AnotherDerived : public Base { virtual EObjectType getType() {return OT_ANOTHER_DERIVED;} };Wenn du jetzt einen Base-Zeiger hast, kannst du einfach durch getType() den eigentlichen Typ erfahren.
So musst du jeweils getType() implementieren, in der anderen Variante musst du stattdessen immer typ im Konstruktor passend setzen.
-
Athar schrieb:
Wenn du jetzt einen Base-Zeiger hast, kannst du einfach durch getType() den eigentlichen Typ erfahren.
Ich sehe keinen Vorteil gegenüber
typeid.Vielleicht sollte shisha mal erklären, was er eigentlich vor hat.
-
krümelkacker schrieb:
Athar schrieb:
Wenn du jetzt einen Base-Zeiger hast, kannst du einfach durch getType() den eigentlichen Typ erfahren.
Ich sehe keinen Vorteil gegenüber
typeid.typeid ist langsam, wenn man den Namen der Klasse braucht, liefert typeid ziemlich unleserliches Zeug (AFAIK ist nicht festgelegt, wie der name() dargestellt werden soll).
Ich würde getType() aber nur virtual machen, wenn das ganze ein Framework wird, welches durch den Nutzer erweitert wird. Wenn nur du der Nutzer bist, kannst du selber dein enum pflegen und in allen abgeleiteten Klassen im Konstruktor den Typ setzen. getType() existiert dann nur in der Basisklasse.
Vielleicht sollte shisha mal erklären, was er eigentlich vor hat.
Das wäre wohl tatsächlich das Beste...
-
Ein
getType()ist aber auch doof. Wenn man nur einenum-Wert zurückgibt, kann man sich die Methode und dasenumgerade so gut sparen und auftypeidzurückgreifen. So muss man sich nämlich nicht um die Konsistenz und Erweiterbarkeit kümmern. Wenn hingegen ein String oder andere Zusatzinformationen zurückgegeben werden, die nicht als reine Typ-IDs fungieren, kann man darüber nachdenken.Aber generell sollte man sich genau überlegen, ob man das gewünschte Verhalten nicht auch mit virtuellen Methoden hinkriegen kann.
l'abra d'or schrieb:
typeid ist langsam
Das hängt wohl von der Implementierung ab. Selbst ein langsames
typeidwäre für mich nicht gerade das Argument, um auf eine schlechtere Implementierung mitgetType()umzusteigen.l'abra d'or schrieb:
wenn man den Namen der Klasse braucht, liefert typeid ziemlich unleserliches Zeug (AFAIK ist nicht festgelegt, wie der name() dargestellt werden soll).
Ja, aber wo ist hier der entscheidende Vorteil von
enum? Damit hast du rein gar keine String-Repräsentation, nicht einmal eine unportable.