PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Vererbung und Konvertierung



Firebird
04-11-2003, 18:58
Hi, hab wieder mal ne Frage :D

Also ich hab eine Liste von Klassen, die natürlich alle gleich sind, wo aber jede eine andere "Tochter"-Klasse von aKlasse enthalten soll.

Die Klassen aus der Liste können diese Tochter-Klassen dann also ganz einfach als aKlasse behandeln, aber jetzt kommt dass Problem mit der Konvertierung.

Soweit ich weiß, kann ich eine Methode in der Tochter-Klasse, die es in aKlasse nicht gibt, von den Listen-Klassen nicht benutzen, da es für sie ein Objekt der aKlasse ist. Es sollen trotzdem alle eine andere Funktion update() enthalten, also definiere ich diese Methode schon in der aKlasse, und überlade (heißt das so?) sie dann in jeder Tochter-Klasse.

Meine Frage ist jetzt, ob, wenn ein Objekt einer Tochter-Klasse als aKlasse bekannt, beim ausführen überladener Methoden die alte Mehode aus aKlasse, oder die neue, überladene, Methode ausgeführt wird.

(Ansonsten könnte ich versuchen dass ganze über Sinals und Slots zu regeln, wobei connect() in den Tochter-Klassen ausgeführt wird, da nur diese wissen von welchem Typ sie sind, aber eigentlich hab ich es nicht vor.)

EDIT:
Hm, der Text ist unlogisch. Wenn alles was ich gesagt hab stimmt, dann geht es logisch nicht. Also gehe ich mal davon aus, dass mein Text nen Fehler hat :)
Um die Situation noch genauer zu beschreiben ein bisschen code:

Die Klasse, die in der Liste verwendet wird:

class Item
{
private:
Item( aKlasse obj );
~Item();
aKlasse* objekt;
// Der Rest ist unwichtig...
};

Methode(n) der Klasse:

Item::Item( aKlasse obj )
{
objekt = obj;
objekt->update();
// Und weiteres...
}

Und hier wird ein Item der Liste angefügt:

void neFunktion()
{
list = new QPtrList<Item>;
list->append( new Item( new aKlassenTochterEins ) );
list->append( new Item( new aKlassenTochterZwei ) );
list->append( new Item( new aKlassenTochterDrei ) );
// und so weiter
}

Hoffe mal das reicht :)
Die Methode update() aus den aKlassenTöchtern benutzt Variablen, die nur die Klassen selber enhalten, also wenn die Methode in aKlasse ausgeführt würde, gäbe es ein paar nicht existierende Variablen, deshalb ist mein Text unlogisch.

Also ne neue Frage:
Wird im Konstruktor von Item die Methode aKlasse::update(), oder die Methode aKlassenTochter::update() ausgeführt?

wraith
04-11-2003, 19:17
Original geschrieben von Firebird

Soweit ich weiß, kann ich eine Methode in der Tochter-Klasse, die es in aKlasse nicht gibt, von den Listen-Klassen nicht benutzen, da es für sie ein Objekt der aKlasse ist. Es sollen trotzdem alle eine andere Funktion update() enthalten, also definiere ich diese Methode schon in der aKlasse, und überlade (heißt das so?) sie dann in jeder Tochter-Klasse.

Meine Frage ist jetzt, ob, wenn ein Objekt einer Tochter-Klasse als aKlasse bekannt, beim ausführen überladener Methoden die alte Mehode aus aKlasse, oder die neue, überladene, Methode ausgeführt wird.

Du deklarierst die Methode update in der Oberklasse als virtual (am besten pure virtual,damit vemeidest du gleich von Anfang an Object-Slicing).
In den Unterklassen überschreibst du diese Methode (achte auf die korrekt Signatur),und wenn du jetzt mit einem Pointer/einer Referenz auf ein Oberklasseobjekt zugreifst,was aber in Wirklichkeit ein Unterklasseobjekt ist,dann wird die Methode der Unterklasse aufgerufen.

Firebird
04-11-2003, 19:25
Ah, THX, das klingt gut :D
Ich hab mich bisher noch nie mit Virtual etc. beschäftigt, wie genau benutzt man es?
"pure virtual bool update();", und dann in den Tochter-Klassen auch noch so, oder nur "bool update();" ?

Hatte grad mein Posting da oben nochmal bearbeitet, aber ich glaub, dass war nicht nötig :)

wraith
04-11-2003, 19:39
Original geschrieben von Firebird

"pure virtual bool update();", und dann in den Tochter-Klassen auch noch so, oder nur "bool update();" ?

pure ist kein Schlüsselwort.
Bsp.


class Oberklasse
{
public:
virtual void update() {/* Leer oder default Implementierung*/ }
virtual void update_2() = 0;//Pure Virtual,es gibt keine Implementierung
};

class Unterklasse : public Oberklasse
{
public:
void update() {/* Implementierung von update für Unterklasse */}
void udate_2() {/* /* Implementierung von update_2 für Unterklasse */*/ }
};

Wenn eine Methode einmal als virtual deklarriert wurde,so ist sie es in allen Unterklassen auch,man hätte in Unterklasse vor update und update_2 noch virtual davor schreiben können,ist aber redundant.
Wenn eine Methode als pure virtual deklarriert ist (siehe update_2 in Oberklasse),dann ist es nicht möglich von Oberklasse eine Instanz zu erzeugen (Zeiger von Oberklasse sind aber möglich).
class Oberklasse ist abstract.
Jede Klasse,die von Oberklasse erbt,muß wenn sie nicht auch abstract sein will,update_2 implementieren.

Firebird
04-11-2003, 20:40
Hab das jetzt mal probiert, bekomme aber folgende Fehler:


unterklasse.h:41: error: base class `Oberklasse' has incomplete type
unterklasse.h:41: warning: `Unterklasse' has virtual functions but non-virtual destructor

Ich weiß nicht ob der erste Fehler was hiermit zu tun hat, weil ich nicht so ganz weiß was mit Typ gemeint ist.
Aber wozu brauche ich einen virtuellen Destruktor?

wraith
04-11-2003, 21:15
Original geschrieben von Firebird
Hab das jetzt mal probiert, bekomme aber folgende Fehler:
unterklasse.h:41: error: base class `Oberklasse' has incomplete type


Du hast wahrscheinlich nur eine Forwardeclaration von Oberklasse im Header von Unterklasse bekannt.
Aber das reicht nicht,binde den Header von Oberklasse ein.



unterklasse.h:41: warning: `Unterklasse' has virtual functions but non-virtual destructor

Aber wozu brauche ich einen virtuellen Destruktor?
Das ist so eine Faustregel,das jede Klasse die virtuelle Funktionen hat,auch eine virtuellen Destruktor braucht.
Denn sonst wird,wenn du delete auf einen Zeiger der Oberklasse aufrufst,aber eigentlich ein Objekt der Unterklasse ist,nur der Destruktor der Oberklasse aufgerufen -> Speicherleck.

Firebird
04-11-2003, 21:49
Original geschrieben von wraith
Du hast wahrscheinlich nur eine Forwardeclaration von Oberklasse im Header von Unterklasse bekannt.
Aber das reicht nicht,binde den Header von Oberklasse ein.

Hm... hab folgendes da:


// Includes
#include <oberklasse.h>

// Klassen
class Oberklasse;


Das ist so eine Faustregel,das jede Klasse die virtuelle Funktionen hat,auch eine virtuellen Destruktor braucht.
Denn sonst wird,wenn du delete auf einen Zeiger der Oberklasse aufrufst,aber eigentlich ein Objekt der Unterklasse ist,nur der Destruktor der Oberklasse aufgerufen -> Speicherleck.

Ok, dann mach ich dat mal (obwohl ich ansonsten - noch - absolut keine Zeigerobjekte lösche).

wraith
04-11-2003, 21:59
Original geschrieben von Firebird
Hm... hab folgendes da:


// Includes
#include <oberklasse.h>


// Klassen
class Oberklasse;
In oberklasse.h wird ja irgendwie sowas stehen


class Oberklasse
{

};

Die Forwarddeklaration ist dann überflüssig.

Btw. für deine Header,die in deinem Verzeichniss liegen,mit include "" arbeiten.



Ok, dann mach ich dat mal (obwohl ich ansonsten - noch - absolut keine Zeigerobjekte lösche).
Es bringt dir keinen Nachteil,und für den nächsten C++ Standard ist sowieso geplant,daß eine Klasse mit virtuellen Funktionen automatisch eine virtuellen Destruktor bekommt.Noch müssen wir da selber drandenken.
Aber dir ist klar,daß du für Polymorphie (virtual...),mit Zeiger bzw. Referenzen arbeiten mußt.

Firebird
05-11-2003, 14:09
Original geschrieben von wraith
In oberklasse.h wird ja irgendwie sowas stehen


class Oberklasse
{

};

Die Forwarddeklaration ist dann überflüssig.

Btw. für deine Header,die in deinem Verzeichniss liegen,mit include "" arbeiten.

Jo, dachte ich eigentlich auch, aber wenn ich nur die Header-Dateien einbinde (egal ob mit </> oder "/") bringt mir der Compiler (fast in jeder Datei) überall wo ich so eine Klasse verwende nen Syntax Error.
Ob das was damit zu tun hat, dass ich in Datei klassea.h die Datei klasseb.h, und in Datei klasseb.h die Datei klassea.h einbinde (was eigentlich eine unendliche Verschachtelung ist, die vom Compiler aber anscheinend ignoriert wird), weiß ich noch nicht so genau...

Vielleicht kommt der error ja da her, dass "class oberklasse;" nicht reicht, sondern auch der Inhalt enthalten sein muss. Das heißt ich bin wieder mal bei dem Problem mit den nicht funktionierenden Includes (Wie bei meinem letzten Thread hier im Forum...).


Aber dir ist klar,daß du für Polymorphie (virtual...),mit Zeiger bzw. Referenzen arbeiten mußt.

Ich arbeite grundsätzlich (naja meistens) nur mit Zeigern... die sind einfach praktischer - auch wenn man sie löschen muss.

anda_skoa
05-11-2003, 14:29
Original geschrieben von Firebird
Jo, dachte ich eigentlich auch, aber wenn ich nur die Header-Dateien einbinde (egal ob mit </> oder "/") bringt mir der Compiler (fast in jeder Datei) überall wo ich so eine Klasse verwende nen Syntax Error.


Dann passt was mit den Headern nicht.
Poste mal die genau Fehlermeldung und wenn möglich den Header.



Ob das was damit zu tun hat, dass ich in Datei klassea.h die Datei klasseb.h, und in Datei klasseb.h die Datei klassea.h einbinde (was eigentlich eine unendliche Verschachtelung ist, die vom Compiler aber anscheinend ignoriert wird), weiß ich noch nicht so genau...

Wäre möglich.
Reicht es denn nicht, wenn du im jeweiligen anderen Header nur die forward declaration der Klasse hast?

Ciao,
_

Firebird
05-11-2003, 15:54
Wäre möglich.
Reicht es denn nicht, wenn du im jeweiligen anderen Header nur die forward declaration der Klasse hast?

Dass hab ich jetzt mal ausprobiert, und es klappt!!
Komisch is nur, dass jetzt auch der andere Fehler und die Warnung von oben weg sind.

Die Warnung müsste eigentlich noch kommen, da der Destructor immernoch "non-virtual" ist, aber die kommt nicht...

THX dann mal... ich hoffe mal jetzt kommen keine Fehler mehr dazu :)

Jetzt grad eben ist mir auch noch eingefallen, dass die Verschachtelung von KDevelop verhindert wird:
#ifndef KLASSE_H
#define KLASSE_H
Also ist dass Problem wirklich gelöst...

Firebird
06-11-2003, 18:18
Sieht so aus, als wäre doch noch nicht alles gelöst.

Mein Problem ist, wenn ich in Unterklasse ein Objekt vom Typ HauptKlasse (die Haupt-Anwendung, die alle möglichen Zeiger etc. enthält, die ich im Programm brauche - in diesem Fall ein Zeiger auf ein Objekt von QSettings - aber nicht durch ne Menge funktionen weiterreichen will..) verwende, dass in OberKlasse definiert ist, bekomme ich folgenden Fehler:


unterklasse.cpp:51: error: invalid use of undefined type `struct Hauptklasse'
oberklasse.h:28: error: forward declaration of `struct Hauptklasse'
Und zwar für jede Stelle in unterklasse.cpp, wo ich das Objekt benutze einmal.

Warum hält der Compiler Hauptklasse für eine Struktur, obwohl es eine Klasse ist!?

Wenn ich jetzt aus oberklasse.h die "forward declaration" "class Hauptklasse;" entferne, bekomme ich natürlich erstmal Syntax Error, und wenn ich "#include "hauptklasse.h"" einfüge (mich wundert, dass dann kein Syntax Error mehr kommt, da KDevelop eigentlich verhindert hat, dass Header-Dateien mehrmals inkludiert bzw. beachtet werden - hab ich ja geschrieben - aber hauptklasse.h schon vorher inkludiert wurde.), bin ich wieder beim gleichen Fehler wie oben (mit dem Unterschied, dass ich die Warnung mittlerweile weg gemacht hab):


unterklasse.h:41: error: base class `oberklasse' has incomplete type

In Zeile 41 steht "class unterklasse : public oberklasse". Ich denk mal, dass - weil ich von Vererbung kaum Ahnung hab - in oberklasse noch etwas wichtiges fehlt, damit ich es vererben kann. Und nochwas: werden nur Öffentliche (Public) Funktionen und Variablen vererbt, oder auch Private?
Mich würde es schon sehr weiterbringen, wenn ich wüsste was mit "type" gemeint ist (Ist der Typ denn nicht "oberklasse" ?).

anda_skoa
06-11-2003, 20:07
Du musst in unterklasse.cpp den Header von Hauptklasse inkludieren.

Im Header reicht die Forward Declaration, die du durch den Oberklasse Header bekommst, aber bei Benutzung der Klasse muss ihre gesamte Deklaration bekannt sein und dazu inkludiert man den Header.

Ciao,
_

Firebird
06-11-2003, 20:23
Ok, das scheint wiedermal zu funktionieren, aber das nächste Problem ist schon wieder da:

Wenn ich Oberklasse::FunktionAusOberklasseVonOberklasse() ausführe, ist die Funktion nicht deklariert.....

Ich glaub bevor ich an meinem Programm weitermache les ich erstmal nochn C++-Buch - 3000 errors am Tag machen mich verrückt :(
Vorallem die Vererbung hab ich wohl noch net so ganz begriffen..

anda_skoa
06-11-2003, 20:26
Original geschrieben von Firebird
Wenn ich Oberklasse::FunktionAusOberklasseVonOberklasse() ausführe, ist die Funktion nicht deklariert.....


Das sollte in Unterklasse wirklich nicht auftreten, sehr eigenartig.
Bist du sicher, dass die Methode in oberklasse.h wirklich deklariert ist und auch nicht private ist?

Ciao,
_

Firebird
06-11-2003, 21:47
Die Oberklasse von der Oberklasse ist QWidget, und die Funktion(en) um die es geht sind hide() und caption()...