Vererbung einer Klasse....Was brauch ich an der Initialisierungsliste?
-
Hallo,
meine Frage hat zwar indirekt was mit Qt zu tun, aber eigenltich gehts nur um die Vererbung. Deswegen stell ich meine Frage mal hier.Also: Ich habe eine Klasse die Uebersicht heißt. Diese Klasse erbt von einer anderen Klasse die QMainWindow heißt.
Jetzt habe ich eine weitere Klasse die Abfrage heißt. Diese erbt von der Klasse Uebersicht.Und das ganze nochmal zur besseren Übersicht:
Klasse 1: QMainWindow (die ist von Qt mir gegeben)
Klasse 2: Uebersicht (die erbt von QMainWindow)
Klasse 3: Abfrage (die erbt von Uebersicht, also von Klasse 2)Mein Problem ist jetzt das ich die 2te Vererbung nicht gebacken kriege.
Hier ist mal meine Uebersicht Klasse:
Uebersicht.h
class Uebersicht : public QMainWindow { Q_OBJECT public: Uebersicht(QWidget *parent = 0); ~Uebersicht(); // weitere Funktionen };
->Also hier sieht man an ": public QMainWindow" das sie von QMainWindow erbt.
Mein Funktionsparameter ist "parent" den ich mit "0" initialisiere. Soweit alles richtig?Uebersicht.h
Uebersicht::Uebersicht(QWidget *parent) : QMainWindow(parent) { //bla bla bla }
Hier der Vollständigkeit halber noch mein Uebersicht-Konstruktor.....
Hier muss ich allerdings zugeben das ich nicht genau weiß was das soll...
Uebersicht(QWidget *parent) : QMainWindow(parent)<->Das erste ist jetzt mein Funktionsparameter meiner Klasse Uebersicht und das zweite ist jetzt der Funktionsparameter der Basisklasse... Wenn ich allerdings eine Instanz dieser Klasse Uebersicht erstelle übergebe ich keine Parameter. Liegt das daran das ich die Funktionsparameter quasi ja mit 0 initialissiert habe?Mein eigenltiches Problem kommt genau hier das ich nicht weiß wie ich jetzt eine vererbte Klasse weitervererbe....
Abfrage.h
class AbfrageFenster : public Uebersicht // Müßte hier dann noch :public QMainwidget stehen? // Weil davon erbt Abfrage ja auch.... { Q_OBJECT public: AbfrageFenster(QWidget *parent = 0); // Was muß ich jetzt hier bei dem Funktions- }; // parameter schreiben? Eigenltich müßte ich // ja den Übergabeparameter von Uebersicht // auch noch mit einbringen oder?
Abfrage.cpp
AbfrageFenster::AbfrageFenster(QWidget *parent) :Uebersicht(QWidget *parent) :QMainWidget(parent) { // bla bla bla }
Speziell bei der Abfrage.cpp Datei weiß ich jetzt ehrlichgesagt nicht was ich da schreiben soll. Hab schon bei Wikipedia nach Initialissierung geschaut aber das hilft mir zumindest in meinem Fall gar nicht weiter...
Hat jemand ne Erklärung? Wäre cool wenn da jemand weiterhelfen könnte.schönen Abend dann noch
mfg Cascoin
-
Im ersten Teil (der Konstruktor von Uebersicht) rufst du per Initialisierungsliste den Konstruktor seiner Basisklasse auf und übergibst dort den Parameter, der von außen vorgegeben wurde. Wenn der Konstruktor ohne Parameter aufgerufen wird, greift der Default-Parameter "QWidget* parent = 0", d.h. als Parameter wird der Null-Zeiger vorgegeben.
Im zweiten Teil (AbfrageFenster) kann es dir egal sein, wovon die direkte Basisklasse abgeleitet ist*. Du mußt nur den Konstruktor deiner direkten Basisklasse aufrufen - der kümmert sich dann selber darum, daß dessen Basis auch initialisiert wird.
*Ausnahme ist bei virtuellen Basisklassen, aber die sind eher selten anzutreffen.
-
Hi,
ok danke für die Antwort.... Das was du im ersten Teil geschrieben hast hab ich auch so verstanden.... Das paßt...
Aber es funzt halt immer noch net.Deswegen poste ich nochmal meinen Code. Zu Klasse Uebersicht ist zu sagen das des einwandfrei funktioniert....
Nur AbfrageFenster macht Probleme.Uebersicht.h
class Uebersicht : public QMainWindow { Q_OBJECT public: Uebersicht(QWidget *parent = 0); ~Uebersicht(); };
Uebersicht.cpp - Nur der Konstruktor......
Uebersicht::Uebersicht(QWidget *parent) : QMainWindow(parent) { // bla bla }
Hier jetzt der 2te Teil...... Wo dann die Probleme kommen....
AbfrageFenster.h
class AbfrageFenster : public Uebersicht { Q_OBJECT public: AbfrageFenster(QWidget *parent = 0, QWidget *parent2 = 0); // Punkt 1: };
AbfrageFenster.cpp - Nur der Konstruktor......
AbfrageFenster::AbfrageFenster(QWidget *parent, QWidget *parent2) :Uebersicht(QWidget *parent) // Punkt 2: { //bla bla bla }
Punkt 1:
Hier müßte ich ja eigentlich von der Basisklasse auch noch die Parameter übergeben. Aber mich verwirrt hier, dass ich ja 2x eigenltich QWidget *parent = 0 hätte.(1x von Basisklasse und 1x von aktueller Klasse).
Schreibe ich dann AbfrageFenster(QWidget *parent = 0, QWidget *parent2 = 0); ???
So zumindest hab ich das im Bsp von Wikipedia verstanden wenn man dort nach Initialisierungsliste sucht.Punkt 2:
Ok, ist gut zu wissen das man sich nur um die direkte Vorfahren-Klasse kümmern muss.
Also in der erste Klammer von AbfrageFenster::AbfrageFenster(xxxxx) steht dann im Prinzip genau das gleiche wie in der Def. der Klasse (AbfrageFenster.h) nur ohne Default Zuweisung...->Also genau das, was ich bei "Punkt 1" geschrieben hab.
Und dann kommt ja der einfache Doppelpunkt, dann die Basisklasse und in der Klammer wieder deren Konstruktoraufruf.So macht das für mich Sinn muss ich zugeben. Leider nicht für den Compiler weil der mir Fehlermeldungen ausspuckt. Und wenn wunderts, mir sagt die Fehlermeldung mal wieder überhaupt nichts.....
Hier mal die Fehlermeldung falls des euch was hilft:
In constructor "AbfrageFenster::AbfrageFenster(QWidget*, QWidget*): expected primary-expression before '*' token }
Also falls jemand weiterhelfen könnte wäre das super....
grüße Cascoin
-
Nein, du mußt dich nicht noch um die Parameter der Großeltern-Klasse kümmern. Wenn es in deinem Design nicht notwendig ist, mehrere Elternfenster zu haben (imho sehr unwahrscheinlich), dann mußt du auch nicht mehrere im Konstruktor verlangen. Der Konstruktor von AbfrageFenster nimmt einen Parameter und übergibt ihn an seine Basisklasse Uebersicht, deren Konstruktor kümmert sich dann selber darum, diesen Parameter an die eigene Basis weiterzureichen:
class Uebersicht : public QMainWindow { Q_OBJECT public: Uebersicht(QWidget *parent = 0); ~Uebersicht(); }; Uebersicht::Uebersicht(QWidget *parent) : QMainWindow(parent) { // bla bla }
und
class AbfrageFenster : public Uebersicht { Q_OBJECT public: AbfrageFenster(QWidget *parent = 0); }; AbfrageFenster::AbfrageFenster(QWidget *parent) : Uebersicht(parent) { //bla bla bla }
Siehst du die Parallelen?
In der Initialisierungsliste des AbfrageFenster-Konstruktor war tatsächlich noch ein Syntaxfehler drin - beim Aufruf einer Funktion gibt man den Typ der Argumente nicht mit an, deshalb hat der Compiler das "QWidget *parent" dort als Multiplikation gedeutet (und ist gescheitert weil QWidget keine Variable ist).
-
Was für einen Sinn macht es, dass du dich schon mit frameworks wie QT auseinandersetzt, wenn du noch nicht mal die elementarsten Grundlagen von C++ kennst?
Du scheinst nicht mal zu wissen wie Initialisierungslisten verwendet werden, geschweige denn hast du Kenntnisse über Vererbung.
Ich würde erstmal ein Grundlagen-Buch empfehlen.
-
Ich dachte das QWidget *parent2 die Parameter für meine aktuelle Klasse sind.
und QWidget *parent die Parameter für meine Eltern-Klasse sind.
Aber stimmt schon, wenn ich für meine aktuelle Klasse keine Parameter habe, dann muss ich ja auch nur den Basisklassen-Parameter übergeben...Und ja, ich sehe die Parallelen.... Muss zugeben das ichs zu allererst auch so probiert habe....aber so hat es leider nicht funktioniert....
Jetzt hab ich geschaut ob der Code in einem neu erstellten Project läuft....
Und das tut er auch.... Also prima....Die Frage ist halt jetzt, wieso zum Teufel der Compiler das in meinem Project, das ich eigenltich bearbeite nicht hinbekommt?
Hab net so Bock alles nochmal neu zu machen....
Ich weiß, es kann wohl ziemlich viele Gründe geben woran das nun liegen könnte....Ich poste mal die Fehlermeldungen: Könnte ja sein dasd das euch was sagt...
undefined reference to `vtable for AbfrageFenster' undefined reference to `vtable for AbfrageFenster' undefined reference to `vtable for AbfrageFenster' undefined reference to `vtable for AbfrageFenster' collect2: ld returned 1 exit status
Naja, wenn jemand ne Idee hat was das bedeuten könnte waers cool.
Ach und ich bin mir ziemlich sicher das ich mich nicht verschrieben hab. Habs glaub 3x kontrolliert....Auf jedenfall noch mal DANKE für die bisherige Hilfe.... Hat mir weitergeholfen und hab was gelernt...
mfg Cascoin
-
Des Problem ist, daß der Compiler aus irgendeinem Grund keine vtable* für deine Klasse bereitgestellt hat. Laut ODR darf diese nur einmal existieren, deswegen sucht sich der Compiler normalerweise eine Übersetzungseinheit aus, wo er sie dranhängt (die Kriterien dazu habe ich nicht im Kopf, aber afair wählt er dazu eine Methode der Klasse aus und packt die VTable in die selbe ÜE wie diese Methode). Wenn er keine geeignete ÜE auswählen kann (oder die ausgewählte Methode vergessen wurde), wird die vtable nicht definiert und der Linker beschwert sich demzufolge.
*das ist eine Liste, mit der die virtuellen Methodenaufrufe zugeordnet werden.
-
Danke CStoll für deine Hilfe.....
[gelöst]