PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [C++]Destruktor der Basisklasse aufrufen?


Gast
2006-05-23, 20:19:39
Hi Leute,

ich habe eine Basisklasse CBase und eine davon abgeleitete Klasse CDeriv, und möchte jetzt im Destruktor von CDeriv den Destruktor von CBase aufrufen, z.B. weil ich im Konstruktor der Basisklasse dynamisch Speicher allokiert habe, der im Destruktor von CBase freigegeben wird, und ich den zugehörigen Code im Destruktor von CDeriv nicht noch einmal schreiben möchte. Die Frage ist nur: geht das?

Folgender Code:

class CBase:
{
public:
//...
~CBase()
{
// gib Speicher frei
}
//...
};

class CDeriv : public CBase
{
public:
//...
~CDeriv();
//...
};

CDeriv::~CDeriv()
{
//...
CBase::~CBase();
}

liefert eine Fehlermeldung (Dev-C++ 4.9.9.2 mit gcc 3.4.2):
in CDeriv::~CDeriv():
no match for call to CDeriv::~CBase()
candidates are CBase::~CBase()

Es ändert sich auch nichts, wenn ich den Destruktor von CBase als virtual deklariere.

Der Namenlose
2006-05-23, 20:40:05
Der Destructor der Basisklasse wird sowieso immer aufgerufen, nachdem der der abgeleiteten Klasse abgearbeitet ist.

Coda
2006-05-23, 21:10:38
Wua. Hungarian Notation *schauder*
SCNR.

Expandable
2006-05-23, 21:43:48
#include <iostream>

class Test
{
public:
~Test()
{
std::cout << "~Test aufgerufen" << std::endl;
}
};

class Derived : public Test
{
public:
~Derived()
{
std::cout << "~Derived aufgerufen" << std::endl;
}
};

void main()
{
Test* t = new Test();
Derived* d = new Derived();

std::cout << "Lösche Test...";
delete t;
std::cout << "Lösche Derived...";
delete d;

return;
}


Ausgabe:
Lösche Test... ~Test aufgerufen
Lösche Derived...~Derived aufgerufen
~Test aufgerufen

Baut man den Destruktor wie folgt um:


~Derived()
{
Test::~Test();
std::cout << "~Derived aufgerufen" << std::endl;
}


ist die Ausgabe:
Lösche Test... ~Test aufgerufen
Lösche Derived...~Test aufgerufen
~Derived aufgerufen
~Test aufgerufen

Mit anderen Worten: Du willst den Destruktor der Parentklasse gar nicht explizit aufrufen, denn dann würdest Du ihn zweimal abarbeiten. MSVC2005 kompiliert den Code aber so problemlos.

Abe Ghiran
2006-05-24, 12:52:40
Und deklarier den Destruktor der Basisklasse mal als virtual.

Grüße, Jan

Gast
2006-05-24, 23:32:10
Hey Leute,

danke, das mit dem automatischen Aufruf des Basisklassen-Destruktor hab ich inzwischen auch rausgefunden :)

Das ist zwar ne ganz praktische Sache, kann aber auch in die Hose gehen: der Basisklassen-Konstruktor wird ja nicht automatisch aufgerufen, den muß man explizit im Konstruktor der abgeleiteten Klassen aufrufen. Tut man dies aber nicht, z.B. weil es in der abgeleiteten Klasse nicht benötigt wird, der Basisklassen-Destruktor dann aber annimmt, daß vom Basisklassen-Konstruktor dynamisch Speicher allokiert wurde (was aufgrund dessen Nichtverwendung nicht passiert ist), und diesen dann freizugeben versucht, dann oha...

del_4901
2006-05-25, 02:14:12
Gast[/POST]']Hey Leute,

danke, das mit dem automatischen Aufruf des Basisklassen-Destruktor hab ich inzwischen auch rausgefunden :)

Das ist zwar ne ganz praktische Sache, kann aber auch in die Hose gehen: der Basisklassen-Konstruktor wird ja nicht automatisch aufgerufen, den muß man explizit im Konstruktor der abgeleiteten Klassen aufrufen. Tut man dies aber nicht, z.B. weil es in der abgeleiteten Klasse nicht benötigt wird, der Basisklassen-Destruktor dann aber annimmt, daß vom Basisklassen-Konstruktor dynamisch Speicher allokiert wurde (was aufgrund dessen Nichtverwendung nicht passiert ist), und diesen dann freizugeben versucht, dann oha...

Das währe mir neu, das der Basisklassenkonstuktor nicht aufgerufen wird, der sohar noch vor dem eigendl. Konstuktor aufgerufen ... das würde ja sonnst alles auch keinen Sinn ergeben.

del_4901
2006-05-25, 02:16:49
.

Expandable
2006-05-25, 13:18:35
#include <iostream>

class Test
{
public:
Test()
{
std::cout << "Konstruktor: Test aufgerufen" << std::endl;
}
~Test()
{
std::cout << "Destruktor: ~Test aufgerufen" << std::endl;
}
};

class Derived : public Test
{
public:
Derived()
{
std::cout << "Konstruktor: Derived aufgerufen" << std::endl;
}
~Derived()
{
std::cout << "Destruktor: ~Derived aufgerufen" << std::endl;
}
};

void main()
{
std::cout << "Erstelle test....";
Test* t = new Test();
std::cout << "Erstelle derived...";
Derived* d = new Derived();

std::cout << "Lösche Test...";
delete t;
std::cout << "Lösche Derived...";
delete d;

return;
}


Ausgabe:
Erstelle test....Konstruktor: Test aufgerufen
Erstelle derived...Konstruktor: Test aufgerufen
Konstruktor: Derived aufgerufen
L÷sche Test...Destruktor: ~Test aufgerufen
L÷sche Derived...Destruktor: ~Derived aufgerufen
Destruktor: ~Test aufgerufen

Also wird der Basiskonstruktor implizit aufgerufen - und zwar vor dem untergeordneten Konstruktor. Außerdem sollte es bzgl. dem dynamischen Allokieren keine Probleme geben. Pointer, die in der abgeleiteten Klasse keine Funktion erfüllen, sollten in abgeleiteten Klassen sowieso nicht verfügbar sein (also private in der Basisklasse) und falls doch, sollten sie immer mit 0 initialisiert werden, dann schadet delete auch nicht.

Xmas
2006-05-25, 15:22:40
Man kann den Basiskonstruktor aber auch explizit in der Initialisierungsliste aufrufen, dann entfällt der implizite Aufruf des Default-Basiskonstruktors natürlich. Das muss man sogar tun wenn die Basisklasse keinen Default-Konstruktor hat.