it-swarm.com.de

virtueller Funktionsaufruf von der Basisklasse

Sagen wir, wir haben:


Class Base
{   
    virtual void f(){g();};
    virtual void g(){//Do some Base related code;}
};

Class Derived : public Base
{   
    virtual void f(){Base::f();};
    virtual void g(){//Do some Derived related code};
};

int main()
{
    Base *pBase = new Derived;
    pBase->f();
    return 0;  
}

Welche g() wird von Base::f() aufgerufen? Base::g() oder Derived::g()?

Vielen Dank... 

45
Gal Goldman

Das g der abgeleiteten Klasse wird aufgerufen. Wenn Sie die Funktion in der Basis aufrufen möchten, rufen Sie an

Base::g();

stattdessen. Wenn Sie die abgeleitete Version aufrufen möchten, die Basisversion jedoch weiterhin aufgerufen werden soll, ordnen Sie an, dass die abgeleitete Version von g die Basisversion in ihrer ersten Anweisung aufruft:

virtual void g() {
    Base::g();
    // some work related to derived
}

Die Tatsache, dass eine Funktion von der Basis eine virtuelle Methode und ein Steuerelement in die abgeleitete Klasse übermitteln kann, wird im Entwurfsmuster der Vorlagenmethode verwendet. Für C++ ist es besser als Non-Virtual-Interface bekannt. Sie wird auch häufig in der C++ - Standardbibliothek verwendet (C++ - Stream-Puffer haben beispielsweise Funktionen pub..., die virtuelle Funktionen aufrufen, die die eigentliche Arbeit erledigen. Beispielsweise pubseekoff ruft die geschützte seekoff auf. Ich habe in dieser Antwort ein Beispiel dafür geschrieben: Wie validieren Sie den internen Zustand eines Objekts?

Es ist der Derived :: g, es sei denn, Sie rufen g im Konstruktor von Base auf. Da der Basiskonstruktor vor der Erstellung des Derived-Objekts aufgerufen wird, kann Derived :: g nicht logisch aufgerufen werden, da er möglicherweise Variablen bearbeitet, die noch nicht erstellt wurden. Daher wird Base :: g aufgerufen.

6
Syed Lavasani

pBase ist ein Zeiger auf eine Basis pBase = neu Abgeleitete gibt einen Zeiger auf eine abgeleitete - Abgeleitete-Basis zurück.

Also ist pBase = new Derived gültig.

pBase verweist auf eine Basis, daher wird Abgeleitetes als Basis betrachtet.

pBase-> f () ruft Derive :: f () auf;

Dann sehen wir im Code:

Ableiten :: f () -> Base :: f () -> g() - aber welche g ??

Nun, es ruft Derive :: g () auf, weil dies das g ist, auf das pBase zeigt.

Antwort: Ableiten :: g ()

5
Jacob

Ich bin mir nicht sicher, ob das kompilieren sollte. Folgende,

Base *pBase = new Derived;

ist ungültig, es sei denn Sie haben:

Class Derived : public Base

Ist es dir gemeint? Wenn das willst du gemeint, 

pBase->f();

Dann würde der Aufrufstack so ablaufen:

Derived::f()
    Base::f()
        Derived::g()
2
user48956

Wenn Sie Ihren Code tatsächlich ausführen, wird Derived :: g () aufgerufen.

1
KJAWolf

Da Sie g() als virtuell definiert haben, wird der am meisten abgeleitete g() in der vtable der Klasse nachgeschlagen und unabhängig vom Typ aufgerufen, auf den Ihr Code aktuell zugreift. 

Siehe C++ FAQ zu virtuellen Funktionen .

1
Thorsten79

Die Methode der abgeleiteten Klasse wird aufgerufen.

Dies liegt daran, dass vtables in Klassen eingeschlossen sind, die über virtuelle Funktionen verfügen, und Klassen, die diese Funktionen überschreiben. (Dies wird auch als dynamischer Versand bezeichnet.) Hier ist, was wirklich los ist: Eine vtable wird für Base erstellt und eine vtable wird für Derived erstellt, da es nur eine vtable pro Klasse gibt. Da pBase für eine Funktion aufgerufen wird, die virtuell ist und überschreibt, wird ein Zeiger auf die vtable für Derived aufgerufen. Nennen Sie es d_ptr, auch bekannt als vpointer:

int main()
{
    Base *pBase = new Derived;
    pBase->d_ptr->f();
    return 0;  
}

Nun ruft der d_ptr Derived::f() auf, der Base::f() aufruft, der dann die vtable betrachtet, um zu sehen, was g() verwendet werden soll. Da der vpointer nur g() in Derived kennt, verwenden wir diesen. Daher wird Derived::g() aufgerufen.

0
Jossie Calderon

Ich denke, Sie versuchen zu erfinden Template Method Pattern

0
Lazin