[C++] inherited destructors

Hi!
Ich möchte für GTK einen Pascal-Wrapper baun, der objektorientiert ist. Dazu hab ich mir GTK-- angeschaut, und da ich leider C++ nicht gut beherrsche, ist mir einiges noch nicht klar:

Wenn der Destructor eine Klasse aufgerufen wird, werden dann automatisch alle Destructoren der Vorgänger-Klassen auch aufgerufen?

Was bedeutet das Schlüsselwort „explicit“ vor einem Constructor?

Wenn „o“ folgendermaßen definiert ist: „MyClass* o;“, was macht dann „destroy o“; Ruft das den Destructor auf?

Wie handelt C++ intern den Aufruf einer Methode? Liegt da am Stack dann zusätzlich zu den Übergabeparametern auch noch „this“? Wie und wo findet die Methode das? Ist es schlimm, wenn die Methode von irgendwo so aufgerufen wird, als währe es eine normale function?

Vielen Dank!

Bye
Hansi

Hi zur"uck,

prinzipiell bist Du bei Bruce Eckel gut aufgehoben, aber konkret:

Ich möchte für GTK einen Pascal-Wrapper baun, der
objektorientiert ist.

Mal bei freepascal.org geguckt, ob es sowas nicht schon gibt?

Wenn der Destructor eine Klasse aufgerufen wird, werden dann
automatisch alle Destructoren der Vorgänger-Klassen auch
aufgerufen?

Du meinst Basisklassen? So aus der H"ufte heraus: Nein. Es k"onnen ja von dort Daten ben"otigt werden, um die abgeleitete Klasse ordentlich zu zerst"oren. Du musst sie also explizit aufrufen, aber auch nur, wenn dort dynamische Daten liegen.

Was bedeutet das Schlüsselwort „explicit“ vor einem
Constructor?

Dies bedeutet, dass der Destructor nicht vom Compiler einfach am Blockende automatisch aufgerufen werden darf, sonder explizit dort stehen muss. Geht auch bei Konstruktoren, impliziter Aufruf bei Array-Allozierung.

Wenn „o“ folgendermaßen definiert ist: „MyClass* o;“, was
macht dann „destroy o“; Ruft das den Destructor auf?

Nein, das ist nur ein Pointer. Erst mit o=new MyClass(…); wird ein Objekt erzeugt. Wird dieses mit delete o; wieder freigegeben, dann wird der Destruktor automatisch aufgerufen. Da k"onnte aber das explicit in die Quere kommen.

Wie handelt C++ intern den Aufruf einer Methode? Liegt da am
Stack dann zusätzlich zu den Übergabeparametern auch noch
„this“?

Ja.

Wie und wo findet die Methode das?

Weil es das erste Argument ist.

Ist es schlimm,
wenn die Methode von irgendwo so aufgerufen wird, als wäre es
eine normale function?

Geht gar nicht. Wenn nicht mit Objekt verbunden, dann gibt es einen Compiler-Fehler, weil er diesen „nackten“ Funktionsnamen nicht kennt.
Teilweise etwas anders ist das mit statischen Klassenmethoden, bei denen muss kein Objekt vorhanden sein, nur der Klassenname.

Ciao Lutz

Hallo Lutz!

prinzipiell bist Du bei Bruce Eckel gut aufgehoben, aber
konkret:

Ist das ein Buch?

Ich möchte für GTK einen Pascal-Wrapper baun, der
objektorientiert ist.

Mal bei freepascal.org geguckt, ob es sowas nicht schon gibt?

Ich schreibe das für FreePascal. Es gibt dort nur eine Unit für GTK, die einfach alle Prozeduren importiert. Es gibt aber keinen OOP Wrapper.
Michael van Canneyt macht zZ für die dt. Zeitschrift Toolbox einen Artikel, hat er gesagt. Darin entwickelt er einen OOP Wrapper. Wir werden zusammenhelfen.

Wenn der Destructor einer Klasse aufgerufen wird, werden dann
automatisch alle Destructoren der Vorgänger-Klassen auch
aufgerufen?

Du meinst Basisklassen? So aus der H"ufte heraus: Nein. Es
k"onnen ja von dort Daten ben"otigt werden, um die abgeleitete
Klasse ordentlich zu zerst"oren. Du musst sie also explizit
aufrufen, aber auch nur, wenn dort dynamische Daten liegen.

Hmm, eigentlich reichte es ja auch, den Destructor der eigentlichen Klasse aufzurufen, die Basis-Klassen-Destruktoren braucht man ja gar nicht, wenn die nix besonderes zu tun haben, oder?

Was bedeutet das Schlüsselwort „explicit“ vor einem
Constructor?

Dies bedeutet, dass der Destructor nicht vom Compiler einfach
am Blockende automatisch aufgerufen werden darf, sonder
explizit dort stehen muss. Geht auch bei Konstruktoren,
impliziter Aufruf bei Array-Allozierung.

Was ist ein Blockende? Is das nacht „}“? Gilt das für den automatische Garbage-Collector?

Ich hab hier nur „explicit“ Constructor, keine Destructor. Was bedeutet es dort? In einer Microsoft-Hilfe steht was von „no implicit type conversion“, der Text rundherum is aber absolut unverständlich. :frowning:

Noch was: Wenn in C++ einer Pointer-Variable, in der vorher ein Zeiger auf einen allozierten Heap-Bereich stand, einfach 0 zugewiesen wird, kommt dann auch der Garbage-Collector?

Wenn „o“ folgendermaßen definiert ist: „MyClass* o;“, was
macht dann „destroy o“; Ruft das den Destructor auf?

Nein, das ist nur ein Pointer. Erst mit o=new MyClass(…);
wird ein Objekt erzeugt. Wird dieses mit delete o; wieder
freigegeben, dann wird der Destruktor automatisch aufgerufen.
Da k"onnte aber das explicit in die Quere kommen.

Hmm, ich glaub, das war ned ganz richtig. Die Klasse is bereits (irgendwie) erzeugt und aufm Heap.

Destructoren sind keine mit „explicit“ deklariert.

Aha, aber Du sagst, der Constructor wird aufgerufen. Das beruhigt mich. :smile:

Ist es schlimm,
wenn die Methode von irgendwo so aufgerufen wird, als wäre es
eine normale function?

Geht gar nicht. Wenn nicht mit Objekt verbunden, dann gibt es
einen Compiler-Fehler, weil er diesen „nackten“ Funktionsnamen
nicht kennt.
Teilweise etwas anders ist das mit statischen Klassenmethoden,
bei denen muss kein Objekt vorhanden sein, nur der
Klassenname.

In GTK (das is plain C) ist ein Feld in einer „struct“ folgendermaßen deklariert:

void (\* draw\_slider) (GtkRange \*range);

Die .h-Datei wird in einer C+±Datei inkludiert. Dort heißt es dann in Range_Class::class_init_function()

klass-\>draw\_slider=draw\_slider\_callback;

wobei klass genau so eine struct wie oben ist.

static void draw\_slider\_callback(GtkRange\* o\_);

ist eine Methode aus der Klasse Range_Class.

Er weist also einer Prozedure-Variabel von C eine C+±Methode zu. Diese Methode wird in den GTL-Libs wie eine normale C-Function aufgerufen.

Is das ok so? Hilft ihm da das „static“? Woher kriegen static-Methoden den „this“?

Bye
Hansi

Hi,

Ist das ein Buch?

http://www.bruceeckel.com , das ber"uhmte Thinking in [C/C++/Java], hat mir gut gefallen. (frei zu runterladen)

[Aha.]

Hmm, eigentlich reichte es ja auch, den Destructor der
eigentlichen Klasse aufzurufen, die Basis-Klassen-Destruktoren
braucht man ja gar nicht, wenn die nix besonderes zu tun
haben, oder?

Richtig, und wenn der Destruktor nichts besonderes macht, muss er nicht deklariert werden, es wird automatisch einer erzeugt.

Was bedeutet das Schlüsselwort „explicit“ vor einem
Constructor?

Sorry, hatte ich wohl Con und De verwechselt. Das ist eine Massnahme zum korrekten Programmieren. Wenn ein Objekt immer mit Parametern initialisiert werden soll, muss man den automatischen Konstruktor verbieten, entweder "uber
private:
MyClass(){}

oder deutlicher als
explicit MyClass(){}

Jeder implizite Aufruf erzeugt jetzt einen Fehler. Z.B.
MyClass A,B;
MyClass T[20];

Was ist ein Blockende? Is das nacht „}“?

Ja, und zwar f"ur alle lokalen Objekte, die im Block deklariert wurden. Also mit { MyClass A(20); …

Gilt das für den:automatische Garbage-Collector?

?? Welcher GC, welche Methode,…

Noch was: Wenn in C++ einer Pointer-Variable, in der vorher
ein Zeiger auf einen allozierten Heap-Bereich stand, einfach 0
zugewiesen wird, kommt dann auch der Garbage-Collector?

Ja, eine einfache Methode, einen Zeiger zu „entladen“. Besser w"are es, auf ein (konstantens) „minimales“ Klassenobjekt zu verweisen, oder etwas, was eine Fehlermeldung bei weiterer Benutzung generiert.

Hmm, ich glaub, das war ned ganz richtig. Die Klasse is
bereits (irgendwie) erzeugt und aufm Heap.

Dann sollte sie im gleichen Block, wo sie erzeugt wurde, auch zerst"ort oder ung"ultig gemacht werden. "Ubergebene Objekte sollten nicht zerst"ort werden. Mit einem GC sollte "uberhaupt kein Destruktor notwendig sein.

In GTK (das is plain C) ist ein Feld in einer „struct“
folgendermaßen deklariert:

void (\* draw\_slider) (GtkRange \*range);

Die .h-Datei wird in einer C+±Datei inkludiert. Dort heißt es:dann in Range_Class::class_init_function()

klass-\>draw\_slider=draw\_slider\_callback;

wobei klass genau so eine struct wie oben ist.

static void draw\_slider\_callback(GtkRange\* o\_);

ist

eine Methode aus der Klasse Range_Class.

Is das ok so? Hilft ihm da das „static“? Woher kriegen
static-Methoden den „this“?

Das ist eine statische Klassenmethode. Diese operiert auf statischen Klassenvariablen, oder es muss explizit das Objekt "ubergeben werden, mit welchem was gemacht werden soll. Die Methode ist an kein Objekt gebunden. Ausserhalb der Klassendefinition w"urde die Funktion als

Range\_Class::draw\_slider\_callback(objectptr);

aufgerufen

Nochmal Ciao

Lutz

Hi!

Noch eine Frage:

Was ist bei einer static Methode anders, als bei einer nicht-static? Ich meine eine nicht-static, die aber trotzdem auch nicht virtual is.

Bye
Hansi

Hi!

http://www.bruceeckel.com , das ber"uhmte Thinking in
[C/C++/Java], hat mir gut gefallen. (frei zu runterladen)

AHH! Danke! Werds mir gleich besorgen!

Jeder implizite Aufruf erzeugt jetzt einen Fehler. Z.B.
MyClass A,B;
MyClass T[20];

Ahhh soooo! Klar! Danke!

Hmm, ich glaub, das war ned ganz richtig. Die Klasse is
bereits (irgendwie) erzeugt und aufm Heap.

Dann sollte sie im gleichen Block, wo sie erzeugt wurde, auch
zerst"ort oder ung"ultig gemacht werden. "Ubergebene Objekte
sollten nicht zerst"ort werden. Mit einem GC sollte "uberhaupt
kein Destruktor notwendig sein.

Das ganze ist ein Event gesteuertes System. Da werden Klassen-Instanzen angelegt, und irgendwo viiiel später wieder gelöscht.

Das ist eine statische Klassenmethode. Diese operiert auf
statischen Klassenvariablen, oder es muss explizit das Objekt
"ubergeben werden, mit welchem was gemacht werden soll. Die
Methode ist an kein Objekt gebunden. Ausserhalb der
Klassendefinition w"urde die Funktion als

Range_Class::draw_slider_callback(objectptr);

aufgerufen

Und erwartet die am Stack auch kein „this“??

Bye
Hansi

Das ganze ist ein Event gesteuertes System. Da werden
Klassen-Instanzen angelegt, und irgendwo viiiel später wieder
gelöscht.

F"ur so etwas komplexes macht man eben Garbage Collection. Ist der letzte Pointer zerst"ort, dann wird der Speicherblock als frei erkannt und automatisch gel"oscht. Je nachdem, wieviel „Intelligenz“ in den GC konstruiert wurde, werden Objekte irgendwo noch registriert oder sie haben eine Methode, die alle enthaltenen dynamischen Objekte durchwandert. (Such mal nach CMM, wenn das interessiert). Das gilt f"ur Mark&Sweep/Compact. Beim Reference Counting muss etwas mehr auf die korrekte Zerst"orung der Objekte geachtet werden. Meist wird sowas dann in „smarte“ Pointerklassen hineinimplemntiert.

Range_Class::draw_slider_callback(objectptr);

aufgerufen

Und erwartet die am Stack auch kein „this“??

Nein, bzw in diesem Falle vertritt objectptr die Rolle des „this“.

Ciao Lutz

Hi!

… Garbage Collection …

Ich will ja gar nix in C++ programmieren! :smile: Ich möchte nur das GTK-- (das in C++ gemacht ist) so weit verstehen, damit ich es dann in Pascal implementieren kann. :smile:

Range_Class::draw_slider_callback(objectptr);

aufgerufen

Und erwartet die am Stack auch kein „this“??

Nein, bzw in diesem Falle vertritt objectptr die Rolle des
„this“.

Hmm, das kapier ich jetzt noch ned ganz. Mal angenommen, die statische Methode is so deklariert:

static void draw\_slider\_callback(int Zahl);

und ich rufe diese in einer anderen Methode auf, schreib ich das dann so:

C.draw\_slider(5);

Stimmt das?

Und wenn ich sie von einer normalen Prozedur aus aufrufe, schreibe ich dann

Klasse.draw\_slider(5,c);

    
    ???
    
    Bye
     Hansi
class Klasse{
public:
 static int delta;
 static void draw\_slider\_callback(int Zahl){delta=Zahl;}
};

Diese kann dann nur auf statische Klassenvariablen zugreifen
(z.B. Konstanten, die von Konstruktoren genutzt werden).

und ich rufe diese in einer anderen Methode auf, schreib ich
das dann so:

Nicht ganz, einfach:

draw\_slider(5);

Der Compiler weiss ja, in welcher Klasse das stattfindet.

Und wenn ich sie von einer normalen Prozedur aus aufrufe,
schreibe ich dann

Auch nicht ganz, sondern:

Klasse::draw\_slider(5);

    
    
    Es ist kein Objekt direkt betroffen, allerdings kann sich das Verhalten einzelner Objektmethoden danach "andern. Insbesondere wird nur eine Integervariable ge"andert. (wobei das alles mit irgenwelchem Zeichnen nix mehr zu tun hatte:wink:.
    
    Ciao Lutz

Hi nochmal!

Diese kann dann nur auf statische Klassenvariablen zugreifen
(z.B. Konstanten, die von Konstruktoren genutzt werden).

Es ist kein Objekt direkt betroffen, allerdings kann sich das
Verhalten einzelner Objektmethoden danach "andern.
Insbesondere wird nur eine Integervariable ge"andert. (wobei
das alles mit irgenwelchem Zeichnen nix mehr zu tun hatte:wink:.

Ahh, ja, dann braucht diese static Methode ja gar kein this? Also brauchts auch ned aufm Stack stehen. Sie is also im Prinzip eine ganz normale Function, wo der Compiler (und nur der) weiß, dass die Felder der Klasse gemeint sind, und nicht extra „Klasse.Delta“ geschrieben weren muß?

Hmm, aaaa! Jetzt wird mir viels klarer! Dann werd ich in Pascal das einfach also normale Prozeduren schreiben. Damit da niemand beleidigt is, weil ihm das „Self“ (=this in C++) abgeht!

Danke nochmal!
Hansi

Hi,

Du meinst Basisklassen? So aus der H"ufte heraus: Nein. Es
k"onnen ja von dort Daten ben"otigt werden, um die abgeleitete
Klasse ordentlich zu zerst"oren. Du musst sie also explizit
aufrufen, aber auch nur, wenn dort dynamische Daten liegen.

Vielleicht versteh ich das falsch … natuerlich werden die Destruktoren der Basisklassen aufgerufen, allerdings erst nachdem der this->destructor fertig ist aus dem oben angesprochenen Grund. Wenn man Pointer auf Basisklassen hat und da ein delete drauf macht sollte man einen virtuellen destrucor in der Basisklasse haben, sonst werden nur die Basisklassendestruktoren aufgerufen (haeufiges Speicherloch).

Was bedeutet das Schlüsselwort „explicit“ vor einem
Constructor?

Die gegebene Erklaerung hakt etwas. Wenn man keine Erzeugung eines Objektes ohne Argumente will brauch man nur einen Konstruktor mit Argumenten zu definieren, dann erzeugt der Compiler keinen Defaultkunstruktor. Wenn man sichergehen will (oder es deutlicher zeigen will) wird der default konstruktor private deklariert.
Zu explicit: Wenn es einen Konstruktor mit nur einem (wie auch immer gearteten) Argument gibt, fuehrt C++ automatische Typ-Konvertierungen zwischen dieser Klasse und dem Typ des einen Arguments durch, wenn das noetig ist. Wenn man das nicht weiss kann man sich natuerlich totsuchen nach derartigen Bugs. Wenn die automatische Typkonvertierung bei einargumentigen Konstruktoren zu verhindern, verwendet man das keyword explicit. Dann kann dieser Konstructor nur explizit aufgerufen werden! Eine andere Moeglichkeit fuer Typkonvertierung ist Ueberladung des = Operators.

Wenn „o“ folgendermaßen definiert ist: „MyClass* o;“, was
macht dann „destroy o“; Ruft das den Destructor auf?

Nein, das ist nur ein Pointer. Erst mit o=new MyClass(…);
wird ein Objekt erzeugt. Wird dieses mit delete o; wieder
freigegeben, dann wird der Destruktor automatisch aufgerufen.
Da k"onnte aber das explicit in die Quere kommen.

delete ruft den destructor auf und gibt den Speicher frei, free (c-funktion) gibt nur den speicher frei, destroy kenn ich nicht. Wenn Du auf einen nichtinitialisierten Pointer ein delete machst wird natuerlich auch der Destruktor aufgerufen und als this wird was komisches uebergeben. Gibt normalerweise nen segmenttion fault.

Gruss

Thorsten

Hi Thorsten!

… Destructor der Basisklassen …

 class Nr1 {
 ...
 ~Nr1() { cout 

Wird dann "~Nr2~Nr1" ausgegeben? Also, anders gefragt, sorgt der C++-Compiler automatisch dafür, daß nachm abarbeiten von ~Nr2() sofort der ~Nr1() ausgeführt wird?



> ... explicit ... nur ein Argumeht im Constructor ... Typ-Konvertierung ...


Wie schaut so eine Typ-Konvertierung aus? Kannst mir dafür bitte ein Beispiel zeigen?

Bye
 Hansi

Hi,

… Destructor der Basisklassen …

class Nr1 {

~Nr1() { cout

Hi,

nachdem ich etwas unsicher bezueglich der Typkonvertierung war, habe jetzt nochmal schnell aus dem besagten Eckels-Buch gepastet (uebrigens mit Abstand das beste Programmierbuch, das ich kenne):

//: C12:AutomaticTypeConversion.cpp
// Type conversion constructor
class One {
public:
One() {}
};
class Two {
public:
Two(const One&amp:wink: {}
};
void f(Two) {}
int main() {
One one;
f(one); // Wants a Two, has a One
} ///:~

Und das laesst sich mit dem explicit verhindern (manchmal ist das natuerlich auch sehr praktisch!).

Gruss

Thorsten

Hallo!

Danke für die Erklärung wegen der Destructor!

class intholder {
private:
int bla;
public:
intholder() : bla(0) {}
intholder(int ini) : bla(ini) {cout

Hi,

Ja no na. Hmm, NEE! Ahhh! asoo, du gibst der Function statt
einer Variable vom Typ „intholder“ einen normalen „int“, und
der macht automatisch eine neue Instanz und nimmt dann gleich
den Constructor fürn Int her???

Genau.

Darf ich mal ganz bescheiden sagen, daß C++ eine Frechheit
ist? Da sind so viele Dinge implizit vorausgesetzt, die man
nie erahnen kann!

Das ist bedauerlicherweise wahr. Fallstricke, Fallstricke, Fallstricke …

Und erst das, was man schreiben muß, damit er was macht! So
mit Templates, usw, was da für kryptische Zeichenkombinationen
zusammenkommen?

Vor allem wenn man die Standardbib (STL) benutzt und ein paar etwas anspruchsvollere Sachen macht … da wirft der Kompiler schonmal Bildschirmfuellende Fehlermeldungen aus (man stellt dann nach langem raetseln fest, dass 99% der Meldung aus der Beschreibung eines Typs besteht …).

Wie zB die Variablenzuweisung da droben im Konstructor? WAS
SOLLN DAS? Da gehört doch ein Gleichzeichen? Neee, C++ kann
das auch anders! Machma mit einer Klammer! Zzzzz!

Das ist C+±Konstruktor-syntax. Die int wird mit dem Int-eigenen Konstruktor initialisiert, daher die Klammern. Und das ganze passiert vor dem Konstruktor-Body, so dass in der Funktion schon Elemente der Klasse initialisisiert sind. Dieser Syntax wird sogar erzwungen, wenn es fuer Klassenmitglieder keinen Default-Konstruktor (sprich ohne Argumente) gibt!

Bin ich froh, daß ich bei meinem Pascal bleiben kann! Das kann
das nämlich auch alles (außer Templates, aber das is eh ned so
wichtig für mich), aber viel viel schöner und logischer!

Bin ich froh, dass ich C++ gelernt habe. Ich kenne zwar kein Pascal aber ein Script-Sprachen und C - C++ ist der Hammer. Die Sprache ist extrem leistungsfaehig, wunderbar zu debuggen … und wenn man sich etwas Muehe gibt entsteht wunderschoener eleganter Code, der sich vergleichsweise gut liest. Auf der anderen Seite erlaubt C++ im Gegensatz zu anderen objektorientierten Sprachen auch richtig dreckige Techniken, so dass man auch toll kryptisch hacken kann, wenn man das will oder muss. Und der Syntax ist auch ueberschaubar. Da kommt man rein.
Ach ja und Templates sind der Hammer. Damit kann man manche Sachen in einem Zehntel (!) der Zeit erledigen!

Gruss

Thorsten