Virtuelles Problem, Virtualtable, Speicherzugriffsfehler, Wer ist Spezialist?



  • Grüß Euch,

    Ich habe ein Problem, daß eigentlich keines ist, da ich weiß an welchem Punkt das Programm scheitert, aber nicht warum bzw. die internen Vorgänge, bezüglich virtueller Methodenüberschreibung und Aufruf der Konstruktoren etc., nicht genau nachvollziehen kann, andererseits bin ich rein zufällig auf dieses "Problem" gestoßen, indem ich in der Basisklasse das Schlüsselvort "virtual" vergessen habe.

    Wahrscheinlich liegts am Virtualtable und einem unzulässigen Verweis.

    Vielleicht ist einer von Euch Spezialist, der mir genau sagen kann, an was es hier genau scheitert.
    Folgend das Programm in stark vereinfachter und nachvollziehbarer Form, bei dem der Speicherfehler bzw. eine Speicherzugriffsverletzung noch auftritt.

    #include <stdio.h>
    
    class Basis
    {
    public:
    
    	Basis(void)
    	{
    		printf("Konstruktor Basis\n");
    	}
    
    	~Basis()
    	{
    		printf("Destruktor Basis\n");
    	}	
    
    	// Hier habe ich das Schluesselwort "virtual" vergessen bzw. weggelassen. ( virtual void Func(void) )
    	void Func(void)
    	{
    		printf("Func von Basis...\n");
    	}
    };
    
    class Abgeleitet : public Basis
    {
    public:
    
    	Abgeleitet(void)
    	{
    		printf("Konstruktor Abgeleitet\n");
    	}
    
    	~Abgeleitet()
    	{
    		printf("Destruktor Abgeleitet\n");
    	}
    
    	virtual void Func(void)
    	{
    		printf("Func von Abgeleitet...\n");
    	}
    
    };
    
    void main()
    {
    	Basis *pBasis;
    
    	pBasis = new Abgeleitet;
    
    	// Loescht man das Objekt, kommt es zu einem Speicherzugriffsfehler, 
    	// nachdem, in Reihenfolge, der Konstruktor der Basisklasse un der abgeleiteten Klasse
    	// und der Destruktor der Basisklasse aufgerufen wird, aber bevor der Destruktor
    	// der abgeleiteten Klasse aufgerufen wird.
    	delete(pBasis);
    }
    


  • Du machst einen Fehler:

    Bei Klassen mit virtuellen Funktionen oder Klassen, von denen andere Abgeleitet werden sollen, sollte der Destruktor IMMER virtuell sein, da sonst bei Objekten, die über einen Zeiger auf die Basisklasse verwaltet werden nur der Destruktor der Basis, aber nicht der der abgeleiteten Klasse verwendet wird.

    Neuer Code:

    #include <stdio.h>
    
    class Basis
    {
    public:
    
        Basis(void)
        {
            printf("Konstruktor Basis\n");
        }
    
        virtual ~Basis() //Diese Destruktor sollte virtual sein
        {
            printf("Destruktor Basis\n");
        }   
    
        // Hier habe ich das Schluesselwort "virtual" vergessen bzw. weggelassen. ( virtual void Func(void) )
        void Func(void)
        {
            printf("Func von Basis...\n");
        }
    };
    
    class Abgeleitet : public Basis
    {
    public:
    
        Abgeleitet(void)
        {
            printf("Konstruktor Abgeleitet\n");
        }
    
        virtual ~Abgeleitet()//Dieser dann auch
        {
            printf("Destruktor Abgeleitet\n");
        }
    
        virtual void Func(void)
        {
            printf("Func von Abgeleitet...\n");
        }
    
    };
    
    int main() //Main MUSS laut Standard einen int zurückgeben
    {
        Basis *pBasis;
    
        pBasis = new Abgeleitet;
    
        // Loescht man das Objekt, kommt es zu einem Speicherzugriffsfehler,
        // nachdem, in Reihenfolge, der Konstruktor der Basisklasse un der abgeleiteten Klasse
        // und der Destruktor der Basisklasse aufgerufen wird, aber bevor der Destruktor
        // der abgeleiteten Klasse aufgerufen wird.
        delete(pBasis);
        return(0);
    }
    


  • Hi Phoemuex,

    Herzlichen Danke für Deine rasche und kompetente Antwort.

    Habs zeitgleich im Grundlagenbuch nachgeschlagen, in der die Notwendigkeit eines virtuellen Destruktors beschrieben ist, aufgrund des Nichtaufrufs des Destruktors der Abgeleiteten Klasse, bei nicht virtueller Vereinbarung.

    Was mich aber noch interessieren würde, wieso es überhaupt zum Absturz, in der unkorrigierten Version, kommt.

    Vielleicht hat irgendwer eine Erkärung hierfür.

    Liebe Grüße Gigabyte



  • Phoemuex schrieb:

    virtual ~Abgeleitet()//Dieser dann auch
        {
            printf("Destruktor Abgeleitet\n");
        }
    

    Warum eigentlich? Das versteh ich irgentwie nicht, bei mir klappt's auch, wenn nur die Basisklasse einen virtuellen Destruktor hat.

    mfg.



  • Ja, wäre nicht zwingend erforderlich, da eine Angabe von "virtuell" des Destruktors in der abgeleiteten Klasse, den Destruktor der Basisklasse automatisch als virtuell markiert.
    Aber alles zwei legitim.



  • Gigabyte schrieb:

    Was mich aber noch interessieren würde, wieso es überhaupt zum Absturz, in der unkorrigierten Version, kommt.

    Nun, das liegt schlichtweg daran, dass der dtor nicht virtuell ist. delete bekommt als Argument ja lediglich einen Zeiger auf die Basisklasse. Und da der dtor nicht virtuell ist, wird delete das Objekt so behandeln, als wäre es ein Basisklassenobjekt. Was es allerdings nicht ist. Dadurch kann es dazu kommen, dass der Compiler Fehler verursacht, je nach Implementation.


Anmelden zum Antworten