2010-01-28 16 views
15

Es ist einfach, die virtuelle Funktion in der öffentlichen Vererbung zu verstehen. Also, was ist der Punkt für die virtuelle Funktion in privater oder geschützter Vererbung?virtuelle Funktion in privater oder geschützter Vererbung

Zum Beispiel:

class Base { 
public: 
virtual void f() { cout<<"Base::f()"<<endl;} 
}; 

class Derived: private Base { 
public: 

void f() { cout<<"Derived::f()"<<endl;} 

}; 

Ist das noch genannt zwingende? Was nützt dieser Fall? Was ist die Beziehung dieser beiden f()?

Danke!

Antwort

11

Privat Erbe ist nur eine Implementierungstechnik, keine ist-ein-Beziehung, wie Scott Meyers erklärt in Effective C++:

class Timer { 
public: 
    explicit Timer(int tickFrequency); 
    virtual void onTick() const; // automatically called for each tick 
    ... 
}; 

class Widget: private Timer { 
private: 
    virtual void onTick() const; // look at Widget private data 
    ... 
}; 

Widget Kunden sollten nicht in der Lage sein, ein Widget zu nennen onTick auf, denn das ist nicht Teil der konzeptionellen Widget-Oberfläche.

+0

Das ist ein anderes gutes Beispiel. – Omnifarious

+0

In der Tat, das ist einfach nur alt, ein gutes Beispiel. Ich habe die falsche Frage beantwortet. Hoppla. :-) – Omnifarious

1
  • Es muss nicht immer auf jede Kombination verschiedener Funktionen geachtet werden. Du darfst sie einfach kombinieren.
  • Ein virtuell geschütztes Member ist für abgeleitete Klassen zugänglich, daher ist es für sie nützlich.
  • Ein virtuelles privates Mitglied ist für Freundesklassen zugänglich, also ist es für sie nützlich.
1

wäre ein Beispiel:

/// Thread body interface 
class runnable 
{ 
public: 

    virtual ~runnable() {} 
    virtual void run() =0; 
}; 

/// Starts OS thread, calls p->run() in new thread 
thread_id start_thread(runnable* p); 

/// Has a private thread 
class actor: private runnable, private noncopyable 
{ 
private: 

    thread_id tid; /// private thread 

public: 

    actor() { tid = start_thread(this); } // here this IS-A runnable 
    // ... 
    virtual ~actor() { stop_thread(tid); } 

private: 

    virtual void run() { /* work */ } 
}; 
+0

-1: Dieses Beispiel * wirklich * muss zeigen, wer ruft run() ' – Potatoswatter

+0

Die Funktion start_thread() natürlich. –

+0

Aber wie nennt man 'run'?Es ist privat. –

1

Sowohl private als auch Vererbung übergeordnete virtuelle Funktionen im privaten/geschützten Basisklasse erlaubt geschützt und weder behauptet, die abgeleitet ist eine Art-of seine Basis.

Durch die geschützte Vererbung können abgeleitete Klassen abgeleiteter Klassen die Vererbungsbeziehung kennen und trotzdem die virtuellen Funktionen überschreiben.

Erbt privat von der Base Klasse in Ihrer Derived Klasse, zerstört alle konzeptionellen Verbindungen zwischen der abgeleiteten und Basisklasse. Die abgeleitete Klasse wird nur in Bezug auf die Basisklasse implementiert, nicht mehr. Private Vererbung ist nur eine Implementierungstechnik und impliziert keine Beziehung zwischen den beteiligten Klassen.

3

Ihre Methode f() wird immer noch überschrieben. Diese Beziehung ist nützlich, wenn das Entwurfsmuster Template Method implementiert wird. Im Grunde genommen würden Sie in der Basisklasse gemeinsame Operationen implementieren. Diese Basisklassenoperationen würden dann eine virtuelle Methode wie Ihre f() aufrufen. Wenn die abgeleitete Klasse f() überschreibt, rufen die Basisklassenoperationen die abgeleitete Version von f() auf. Dadurch können abgeleitete Klassen den Basisalgorithmus beibehalten, aber das Verhalten an ihre Bedürfnisse anpassen. Hier ist ein einfaches Beispiel:

#include <iostream> 

using namespace std; 

class Base 
{ 
public: 
    virtual void f() { cout<<"Base::f()" << endl; } 
protected: 
    void base_foo() { f(); } 
}; 

class DerivedOne: private Base 
{ 
public: 
    void f() { cout << "Derived::f()" << endl;} 
    void foo() { base_foo(); } 
}; 

class DerivedTwo: private Base 
{ 
public: 
    void foo() { base_foo(); } 
}; 

int main() 
{ 
    DerivedOne d1; 
    d1.foo(); 

    DerivedTwo d2; 
    d2.foo(); 
} 

Hier ist das Ergebnis zur Laufzeit:

$ ./a.out 
Derived::f() 
Base::f() 

Beide abgeleiteten Klassen nennen die gleiche Basisklasse Betrieb aber das Verhalten ist für jede abgeleitete Klasse.

Verwandte Themen