Funktionszeiger und klasse



  • hallo,
    ich frage mich folgendes:

    einen zeiger "klassenzeiger" auf eine klasse "Klasse1"deklariere.

    ich habe eine weitere klasse, die von klasse1 abgeleitet und gleichzeitig erweitert bzw. funktionen überschrieben wurde(n) (Ableitungsklasse).

    führt so eine deklaration auf dauer zu einem fehler ?

    Klasse *Klassenzeiger = new Ableitungsklasse;

    es wird anstandslos compiliert und ausgeführt, aber führt das nicht zu fehlern ?



  • An dem Code-Schnipselchen ist noch alles in Ordnung, nur solltest du dafür einige Punkte beachten:

    • Die Basisklasse benötigt einen virtuellen Destruktor, sonst wird dein Objekt von delete nur halb gelöscht
    • alle wichtigen Funktionen der Klasse sollten virtuell sein, sonst führt Klassenzeiger->Methode() nur die Methode der Basisklasse aus
    • du kannst auf diesem Weg nur Funktionen der Basisklasse verwenden


  • Die Basisklasse benötigt einen virtuellen Destruktor, sonst wird dein Objekt von delete nur halb gelöscht

    ähm saublöde frage wie muss der dann aussehen ?

    virtual ~Basisklasse() = 0; ?

    was muss da denn ausgeführt werden, damit die abgeleitete klasse komplett gelöscht wird ?

    alle wichtigen Funktionen der Klasse sollten virtuell sein, sonst führt Klassenzeiger->Methode() nur die Methode der Basisklasse aus

    jepp, das ist schon so 🙂

    du kannst auf diesem Weg nur Funktionen der Basisklasse verwenden

    auch das ist mir recht, da die basisklasse alle funktionsdeklarationen enthalten soll, die man braucht. die in der abgeleiteten klasse sollten nicht direkt angesprochen werden können.



  • fragenmacher schrieb:

    Die Basisklasse benötigt einen virtuellen Destruktor, sonst wird dein Objekt von delete nur halb gelöscht

    ähm saublöde frage wie muss der dann aussehen ?

    virtual ~Basisklasse() = 0; ?

    Fast, nur das "=0" ist überflüssig.

    Das Problem mit dem Destruktor ist, daß delete üblicherweise den statischen Typ des Objekts nutzt, um den Destruktor zu finden - das heißt er würde nur den Basis-Teil löschen und neue Elemente der abgeleiteten Klasse stehen lassen.
    Indem du den Destruktor virtuell definierst, landet er in der vtable der Klasse und beim delete erreichst du dann die "richtige" Version (sprich: den Destruktor der abgeleiteten Klasse).

    was muss da denn ausgeführt werden, damit die abgeleitete klasse komplett gelöscht wird ?

    Einfach ein "virtual" vor den Destruktor zu setzen reicht aus - den Rest kannst du, wenn nötig, ganz normal erledigen (nur für den Fall, daß du dich von Hand mit der Speicherverwaltung rumschlagen mußt).



  • perfekt! danke 🙂



  • CStoll schrieb:

    An dem Code-Schnipselchen ist noch alles in Ordnung, nur solltest du dafür einige Punkte beachten:
    [list][*]Die Basisklasse benötigt einen virtuellen Destruktor, sonst wird dein Objekt von delete nur halb gelöscht

    Das Problem mit dem Destruktor ist, daß delete üblicherweise den statischen Typ des Objekts nutzt, um den Destruktor zu finden - das heißt er würde nur den Basis-Teil löschen und neue Elemente der abgeleiteten Klasse stehen lassen.

    Das ist eine gefährlich Vereinfachung und ein weit verbreiteter Irrtum: ein delete über einen Basisklassenzeiger, der auf ein abgeleitetes Objekt zeigt führt zu *undefiniertem* Verhalten, nicht zu einem fehlenden Aufruf des Dtors der abgeleiteten Klasse. Das ist ein wichtiger Unterschied, den man spätestens dann erkennt, wenn kleine grüne Männchen aus dem Computer steigen und einem den Hintern versohlen.



  • aber wie soll man denn dann solche objekte löschen, wenn delete auf basiszeiger undefiniertes verhalten auslöst?

    // b1, b2 erben von b, b hat virtuellen desturktor
    b* B = NULL;
    int a;
    cin >> a;
    if(a == 1)
      B = new b1;
    else
      B = new b2;
    
    // mach was
    
    delete B;
    

    wenni ch doch nicht weiß, worauf B nun zeigt, wie soll ich es dann löschen...?



  • Maxi schrieb:

    wenni ch doch nicht weiß, worauf B nun zeigt, wie soll ich es dann löschen...?

    Die Antwort ist in diesem Thread bereits mehrfach gegeben worden...



  • HumeSikkins schrieb:

    Das ist eine gefährlich Vereinfachung und ein weit verbreiteter Irrtum: ein delete über einen Basisklassenzeiger, der auf ein abgeleitetes Objekt zeigt führt zu *undefiniertem* Verhalten, nicht zu einem fehlenden Aufruf des Dtors der abgeleiteten Klasse. Das ist ein wichtiger Unterschied, den man spätestens dann erkennt, wenn kleine grüne Männchen aus dem Computer steigen und einem den Hintern versohlen.

    gilt das nur für nicht-virtuelle destruktoren? hört sich so allgemein an



  • Das ist eine gefährlich Vereinfachung und ein weit verbreiteter Irrtum: ein delete über einen Basisklassenzeiger, der auf ein abgeleitetes Objekt zeigt führt zu *undefiniertem* Verhalten, nicht zu einem fehlenden Aufruf des Dtors der abgeleiteten Klasse. Das ist ein wichtiger Unterschied, den man spätestens dann erkennt, wenn kleine grüne Männchen aus dem Computer steigen und einem den Hintern versohlen.

    soll ich daraus schliessen, dass man also so etwas wie:

    basisklasse *basis:
    basis = new abgeleiteteklasse;

    also nicht so einfach zu realisieren ist, weil man die objekte hinterher nicht los wird ?

    ich meine selbst mit dem virtuellen destruktor ?

    wie löst man das problem denn dann ?



  • Keine Panik. Der virtuelle Destruktor löst das Problem.



  • Keine Panik. Der virtuelle Destruktor löst das Problem.

    Exakt. Meine Aussage bezog sich auf die Geschichte mit einem nicht-virtuellen Dtor.
    Um alle Mißverständnisse auszuschließen: wenn man über einen Base-Zeiger löschen will:
    virtueller Dtor: gut
    nicht-virtueller Dtor: böse (Begründung: Grüne Männchen)


Log in to reply