Was ist eine virtuelle Member-Funktion



  • Hi Leute,
    ich bin noch Anfänger und beim lernen auf den Begriff virtuelle Member-Funktion gestoßen. Leider Stand dazu keine weitere Erklärung.Meine Frage . Was ist das ? und muß ich diesem Funktion selber ertsellen?

    Für Eure Hilfe schon jetzt vielen Dank

    Gruß Morse



  • Hallo,
    eine virtuelle Memberfunktion ist eine Methode die virtuell deklariert wurde (mittels des Schlüsselwortes virtual).
    Die Adresse einer solchen Funktíon wird in einer virtuellen Methodentabelle abgelegt. Jedes Objekt einer Klasse mit virtuellen Methoden besitzt einen Zeiger auf diese VMT. Virtuelle Methoden werden in abgeleiteten Klassen überschrieben (wichtig: nicht überladen). Bei dieser Überschreibung wird dann die nun gültige Adresse in die VMT eingetragen. Dieses Verhalten braucht man für die Polymorphie und die späte Bindung. Ein Beispiel: Du hast einen Zeiger auf eine Basisklasse. An diesen Zeiger hängst du jetzt zur Laufzeit ein Objekt einer abgeleiteten Klasse. Rufst du jetzt eine nicht virtuelle Methode auf, wird immer die der Basisklasse aufgerufen, da der statische Typ ja Zeiger auf Basisklasse ist. Rufst du hingegen eine virtuelle Methode auf, wird die richtige Methode (also die der abgeleiteten Klasse) aufgerufen, da sich ja ihre Adresse in der VMT befindet.
    Virtuelle Memberfunktionen braucht man, um ein bestimmtes Interface schon in einer Basisklasse anbieten zu können. Die abgeleiteten Klassen müssen (bzw. können) dieses Interface dann implementieren.

    Hm, keine gute Erklärung.
    Du solltest mal in deinem bevorzugten C++-Buch unter den Wörtern Polymorphie, späte (dynamische Bindung) und natürlich virtuelle-Memberfunktionen nachschlagen. Dort wirst du sicher eine bessere Erklärung finden.



  • @MORSE

    Hallo!

    Trag mal zusammen was ich über die Dinger weiss:

    Also, eine Virtuelle Elementfunktion wird erzeugt, indem man eine non-static Elem.funktion in einer Klassendefinition mit dem Spezifizierer "virtual" definiert bzw. diese deklariert und ausserhalb der Klasse ohne "virtual" dann definiert. Man erzeugt auch eine virtuelle F., indem man die in einer Basiskl. als virtuell definierte in einer abgel. Klasse überschreibt (Später mehr).

    Der Trick an der Sache ist, daß wenn Du über einen Basiskl.zeiger bzw. Referenz auf ein Objekt der abgel. Klasse verweist und eine Elementfunktion aufrufst wird normalerweise immer die Basisklassenversion dieser Funk. aufgerufen, da Du über einen Basiskl.zeiger den Aufruf tätigst.
    D.h. es zählt der Datentyp des Zeigers, welche F. aufgerufen wird.

    Hast Du dagegen virtuelle El.f. wird die F. der abgel. Klasse aufgerufen, da Du auf ein Objekt der abgel. Klasse verweist und bei virt. F. nicht meht der Typ des Zeigers entscheidend ist, sondern der Typ des Objektes auf das der Zeiger verweist.

    Diese Fähigkeit, virtueller F. mit ein und demselben Aufruf verschiedene Versionen der virt. F. aufzurufen (nämlich immer die auf deren Klasse (objekt) du mit dem Zeiger verweist) nennt sich Polymorphie. Und eine Klasse mit virt. Funktionen nennt sich Polymorphe Klasse.

    Ganz wichtig:

    Damit Polymorphie erst zustande kommt müssen folgende Punkte gegeben sein:

    1. Klassenhirarchie mit mehr als einer Ebene (also Basis u. mind. 1 abgel.)
    2. In der Basiskl. muss El.f. mit virtual definiert/deklariert werden.
    3. Die abgel. Klasse/n muss über eine eigene Version der virtue.f. der Basiskl. verfügen (indem man sie in der abgel. Klasse mit gleicher Signatur und Typ des Rückgabewertes redefiniert - man sagt auch überschreibt)
    Damit ist sie auch ohne Spezifizierer virtual nochmal hinzuzufügen virtuell.

    Beispiel:

    class A{
    public:
    virtual int func(int a)
    {
    return(0);
    }
    
    class B : public A
    {
    public:
    int func(int a)
    {
    return(0);
    }
    

    Die El.f. der Basiskl. ist virtuell und auch die in der abgel. Klasse, da sie mit gleicher Signatur und Typ des Rückgabewertes redefiniert wird.

    Über:

    A *pointer;
    B obj;
    
    pointer=&obj;
    
    pointer->func(100);
    

    wird die F. der abgel. Klasse aufgerufen.

    Hält man sich nicht an die Regeln des redefinierens ist die F. in der abgel. Klasse nicht virtuell. Selbst wenn sie mit gleichem Namen überschrieben wird, aber mit untersch. Signatur. Muss eben alles gleich sein.

    Du kannst auch eine Ebene in der Klassenhirarchie auslassen und es geht trotzdem:

    class A{
    public:
    virtual void func(void)
    {}
    };
    
    class B : public A
    {};
    
    class C : public B
    {
    public:
    void func(void)//Die ist virtuell
    {}
    };
    
    // Und jetzt:
    A *pointer;
    B obj;
    C obj_2;
    
    pointer=&obj_2;
    
    pointer->func();
    //Die von C wird aufgerufen.
    
    pointer=&obj;
    
    pointer->func();
    //Die von A wird aufgerufen, da B keine virt. E.f enthält.
    

    Dazu gibts ne Regel:

    Definiert man in einer Basiskl. eine virtuelle Elementfunktion und verweist mit einem Zeiger dieser Klasse auf ein Objekt einer abgel. Klasse, die diese E.f: nicht überschreibt, so wird die Version der virtuellen F. aufgerufen, welche Element einer Klasse ist, die in der Klassenhirarchie am nähesten über der anderen Klasse steht.

    Hört sich blöd an. Beispiel:

    class A
    {
    public:
    virtual void func(void){}
    };
    class B : public A
    {
    void func(void){}
    };
    class C : public B
    {};
    
    A *pointer;
    C obj;
    pointer=&obj;
    pointer->func();
    //Die von B wird aufgerufen;
    

    Du siehst hier:

    Nicht der Zugriffsstatus der virtuellen Funktion, welche aufgerufen wird ist ausschlaggebend für einen Zugriff, sondern der Zugr.status der virtuellen F., welche sich in der Klasse befindet, von deren Typ auch der Zeiger ist über den ich den Aufruf tätige.

    Ich hoffe, das hilft ein bissl.
    Das mit der VMT und dem Pointer darauf erspar ich mir, wenn Du willst kann ich dazu mal wann anders schreiben...

    Zeit drängt...

    mfg madmax

    [ 07.07.2001: Beitrag editiert von: class CMarcus ]


Anmelden zum Antworten