Wie mache ich eine Klasse virtuell



  • virtual ~object() = 0;
    

    so macht man den d'tor virtuell.



  • lucky_tux schrieb:

    Warum soll er den Destruktor rein-virtuell machen? Das ist ein wiederspruch in sich. Um Instanzen von einer abgeleiteten Klassse zu machen, müssen alle rein-virtuellen Fkt. überschrieben werden.

    Falsch, sie müssen von der abgeleiteten Klasse definiert werden.

    Man soll den Destruktor als virtual deklarieren, damit bei gegebener Speicherverwaltung z.B. mit Zeigern der richtige Destruktor aufgerufen wird.

    Dafür macht man ihn virtuell. Rein-virtuell macht man ihn allerdings aus von mir oben genanntem Grund, nämlich um die Klasse abstrakt zu machen.

    1310-Logik: Nein, der Destruktor muss definiert werden, also so:

    virtual ~object() = 0
    {
        // ...
    }
    


  • Danke erstmal
    Werd den Detonator mal virtuell setzten und dann schauen ob es geht.

    @Michael
    C/C++ Code:
    virtual ~object() = 0
    {
    // ...ist diese leere Zeile nötig?
    }



  • Michael E. schrieb:

    1310-Logik: Nein, der Destruktor muss definiert werden, also so:

    virtual ~object() = 0
    {
        // ...
    }
    

    huch ach ja, wieder was vergessen. copy paste ist verfänglich..
    thx

    virtual ~object() = 0 {}
    

    So gehts doch auch oder?
    Dann brauch ich keine Implementation in der *.cpp Datei, oder nicht?



  • Gast1634416 schrieb:

    @Michael
    C/C++ Code:
    virtual ~object() = 0
    {
    // ...ist diese leere Zeile nötig?
    }

    Nö, is ne Kommentarzeile, da kommt halt der Inhalt des Destruktors rein, sofern du überhaupt was reinschreiben willst.

    1310-Logik: Türlich geht das auch. Kannst du auch in der Header-Datei stehen lassen.



  • Nein so geht es nicht! Total falsche Logik!

    Virtuelle Methoden sind nicht zu verwechseln mit rein-virtuellen Methoden. Die Deklaration als virtual besagt nur, dass wenn die Methode von einer abgeleiteten Klasse überschrieben wird bei dem gebrauch von Basisklassenzeigern die richtige Methode aufgerufen wird.

    Für rein-virtuelle Methoden gilt das gleiche. Nur kommt ein sehr entscheidender Punkt hinzu: Die Deklaration als rein-virtuell (virtual /* ... */ =0; ) besagt, dass noch keine Implementierung zu dem jetzigen Zeitpunk möglich ist. Man kann die Funktion nicht definieren!! Dieses Konzept dient allein dem Gebrauch in gemeinsamen Schnittstellen. Die Methode wird in den abgeleiteten Klassen implementiert. Geschieht dies nicht handelt es sich bei der abgeleiteten Klasse automatisch um eine rein-virtuelle / abstrakte Klasse.

    Michael E: Ich glaube du hat mich nicht verstanden. Vlt verwechselst du virtuelle Methoden mit rein-virtuellen Methoden (ein himmelweiter Unterschied). Wenn man den Destruktor als rein-virtuell deklariert, dann darf es in der Klasse keine Implementierung geben, diese müsste in der abgeleiteten Klasse vorkommen. Destruktoren lassen sich aber nicht überschreiben. Das ist ein Wiederspruch! 🙂

    Wenn ich meinen Compiler zitieren darf.

    class Test
    {
      public:
        Test() {}
        virtual ~Test() =0 {}
    };
    
    int main()
    {
    }
    

    Das quitiert der Compiler mit folgenden Fehlermeldungen
    main.cpp:5: error: Fehler beim Parsen before {' token main.cpp:5: error: missing ';' before right brace main.cpp:6: error: Fehler beim Parsen before}' token

    class Test
    {
      public:
        Test() {}
        virtual ~Test() =0; // {}
    };
    
    class T2 : Test
    {
      public:
        T2() {}
        virtual ~Test()
        {
        }
    
    int main()
    {
    }
    

    main.cpp:14: error: destructor `Test' must match class name `T2'
    main.cpp:19: error: Fehler beim Parsen at end of input

    Glaubt ihr es mir jetzt? 🙂



  • Hmm jo, ich hab mich in der Hinsicht vertan, dass rein-virtuelle Funktionen einen Körper haben dürfen (Hinweis: MSVC++ 2003 erlaubts).

    lucky_tux schrieb:

    Destruktoren lassen sich aber nicht überschreiben. Das ist ein Wiederspruch! 🙂

    Hier liegst du allerdings falsch. Meyers benutzt z. B. in "Mehr Effektiv C++ Programmieren" Richtlinie 33 einen rein-virtuellen Destruktor.

    MECP Richtlinie 33 schrieb:

    [...]aber bei seltenen Gelegenheiten sind Sie damit konfrontiert, daß Sie eine Klasse wie AbstractAnimal erzeugen müssen, in der keine der Funktionen natürlicherweise rein virtuell ist. In solchen Fällen ist das übliche Vorgehen, den Destruktor rein virtuell zu machen; [...]

    Außerdem sagt der Standard folgendes unter 12.4.7:

    A destructor can be declared virtual or pure virtual; if any objects of that class or any derived class are created in the program, the destructor shall be defined. If a class has a base class with a virtual destructor, its destructor (whenever user- or implicitly-declared) is virtual.

    Also ist mein Vorgehen, nämlich eine Klasse abstrakt zu machen, indem man den Destruktor rein-virtuell macht, richtig.



  • struct foo
    {
      virtual ~foo() = 0;
    };
    foo::~foo() { }
    
    struct bar : foo
    {
      virtual void whatever() = 0;
    };
    void bar::whatever() { std::cout << "..." << std::endl; }
    
    struct baz : bar
    {
      void whatever();
    };
    void baz::whatever() { bar::whatever(); }
    


  • Man kann die Funktion nicht definieren!!

    Doch und ob man das kann.

    ISO Standard 10.4/2 schrieb:

    An abstract class is a class that can be used only as a base class of some other class; no objects of an abstract class can be created except as subobjects of a class derived from it. A class is abstract if it has at least one pure virtual function. A virtual function is specified pure by using a purespecifier (9.2) in the function declaration in the class declaration. A pure virtual function need be defined only if explicitly called with the qualifiedid syntax (5.1).

    Folgender Code ist absolut korrekt:

    class Foo{
    public:
      virtual void bar()=0;
    };
    
    void Foo::bar(){
    
    }
    

    Bedenkte ich kann Foo::bar immer aufrufen wenn ich Foo::bar und nicht nur bar schreibe.

    Da ein Destruktor immer implizit den Destruktor der Basisklasse aufruft muss dieser definiert sein.

    Was allerdings nicht geht ist folgendes

    class Foo{
    public:
      virtual void bar()=0{};
    };
    

    Eine pure virtuelle Funktion kann nicht in der Klassendefinition definiert werden.

    Wieso er bei deinem zweitem Bespiel meckert sollte offensichtlich sein.



  • class Basis
    {
    public:
      virtual ~Basis() =0;
    };
    
    Basis::~Basis()
    { /* ... */ }
    
    class Abgeleitet : public Basis
    {
    public:
      virtual ~Abgeleitet() =0;
    };
    
    Abgeleitet::~Abgeleitet()
    { /* ... */ }
    
    int main()
    {
      // Basis a;
      Abgeleitet a;
    }
    

    main.cpp: In function int main()': main.cpp:28: error: cannot declare variable \a' to be of type `Abgeleitet'
    main.cpp:28: error: because the following virtual functions are abstract:
    main.cpp:21: error: virtual Abgeleitet::~Abgeleitet()
    main.cpp:21: error: virtual Abgeleitet::~Abgeleitet()

    Dass es nicht möglich ist eine Instanz von der Klasse Basis zu erstellen ist klar, da es sich hiebei um eine rein-virtuelle Schnittstelle handelt. Dieses Interface dient der Klasse Abgeleitet als Basisklasse. Wenn es stimmt, was du sagst, muss es möglich sein eine Instanz von der Klasse Abgeleitet zu erstellen, _ohne_ die Deklaration der Klasse Basis zu veränder. Wenn du mir eine Möglichkeit zeigst, eine Instanz von der Klasse Abgeleitet zu erzeugen muss ich eingestehen, dass du Recht hast... Jetzt bin ich gespannt!



  • Bitteschön

    class Basis
    {
    public:
      virtual ~Basis() =0;
    };
    
    Basis::~Basis()
    { /* ... */ }
    
    class Abgeleitet : public Basis
    {
    public:
      virtual ~Abgeleitet();
    };
    
    Abgeleitet::~Abgeleitet()
    { /* ... */ }
    
    int main()
    {
      // Basis a;
      Abgeleitet a;
    }
    

    Du hast abgeleitet (unabsichtlich?) ebenfalls zu ner abstrakten Klasse gemacht.



  • Keiner hat behauptet, das alle pure virtual sein sollen. Irgendwann muß sich das ändern. Das hat aber auch keiner anders behauptet, worauf Du also gespannt bist ist mir schleierhaft.

    Das hingegen:

    class Basis
    {
    public:
      virtual ~Basis() =0;
    };
    
    Basis::~Basis()
    { /* ... */ }
    
    class Abgeleitet : public Basis
    {
    public:
      virtual ~Abgeleitet(); // = 0;
    };
    
    Abgeleitet::~Abgeleitet()
    { /* ... */ }
    
    int main()
    {
      // Basis a;
      Abgeleitet a;
    }
    

    geht wunderbar, und ich habe nicht die Deklaration von Basis verändert, ganz wie gewünscht. Destruktor rein-virtuell und mit Definition schliessen sich also nicht aus. 🤡



  • Alle rein-virtuellen Methoden müssen überschrieben werden, damit von einer Klasse instanzen gemacht werden können. Ich bin fest davon ausgegangen, dass man den Destruktor einer Klasse nicht überschreiben kann, da sich die Signatur des Destruktors ändert. Du hast gewonnen und ich hab noch ein wenig dazugelernt! 🙂
    Ich habe mich zwar mit Sachen wie z.B. die Metaprogrammierung beschäftigt, aber dass man Destruktoren rein-virtuell deklarieren kann das war mir neu...



  • Ich wusst doch, dass ich irgendwo gelesen hab, dass virtuelle Funktionen nen Körper haben dürfen... Naja, jetzt werd ich mirs merken 🙂



  • rein virtuelle Funktionen dürfen so oder so einen Funktionskörper sprich eine Definition haben, das ist keine Frage. Sicher meinst du die rein-virtuellen Funktionen.

    Das ist schon ein wenig verwirrend, die Ähnlichkeit der beiden Begriffe und die doch teils völlig unterschiedliche Anwendung 🙂

    Aber nun gut ich glaube jetzt hat sich das Thema ausdiskutiert 🕶



  • Türlich, hab das "rein-" vergessen.



  • Also es gibt virtuelle Klassen diese funktion dient jedoch nicht dazu das du von einer Klasse erben kannst (das geht immer).
    Wenn eine Klasse virtual deklariert wurde dann verhindert das die Klasse ausversehen 2mal geerbt wurde.
    Bsp:

    Klasse A
    Klasse B
    Klasse C
    Klasse D

    Die Klassen B und C erben von A und D erbt von B und C
    Jetzt enhält D zweimal A(was zu einem kompilerfehler führt).
    Das kann man verhindern indem man B und C virtual von A erben läss.



  • tobZel schrieb:

    Wenn eine Klasse virtual deklariert wurde dann verhindert das die Klasse ausversehen 2mal geerbt wurde.

    Das nennt sich virtuelle Vererbung :p


Anmelden zum Antworten