Die Frage im Thema deutet auf eine ziemlich häufige Verwirrung hin. Die Verwirrung ist häufig genug, dass C ++ FAQ lange Zeit gegen die Verwendung privater Virtuals plädierte, weil Verwirrung eine schlechte Sache zu sein schien.
Um die Verwirrung zuerst zu beseitigen: Ja, private virtuelle Funktionen können in den abgeleiteten Klassen überschrieben werden. Methoden abgeleiteter Klassen können keine virtuellen Funktionen aus der Basisklasse aufrufen, sie können jedoch ihre eigene Implementierung für sie bereitstellen. Laut Herb Sutter ermöglicht eine öffentliche nicht virtuelle Schnittstelle in der Basisklasse und eine private Implementierung, die in den abgeleiteten Klassen angepasst werden kann, eine bessere "Trennung der Schnittstellenspezifikation von der Spezifikation des anpassbaren Verhaltens der Implementierung". Mehr dazu lesen Sie in seinem Artikel "Virtualität" .
Der von Ihnen vorgestellte Code enthält jedoch noch eine weitere interessante Sache, die meiner Meinung nach etwas mehr Aufmerksamkeit verdient. Die öffentliche Schnittstelle besteht aus einer Reihe überladener nicht virtueller Funktionen, und diese Funktionen rufen nicht öffentliche, nicht überladene virtuelle Funktionen auf. Wie in der C ++ - Welt üblich, ist es eine Redewendung, es hat einen Namen und natürlich ist es nützlich. Der Name ist (Überraschung, Überraschung!)
"Öffentliche überladene Nicht-Virtuals rufen geschützte nicht überladene Virtuals auf"
Es hilft , die Ausblendungsregel richtig zu verwalten . Sie können mehr darüber lesen hier , aber ich werde versuchen , es kurz zu erklären.
Stellen Sie sich vor, dass virtuelle Funktionen der Engine
Klasse auch ihre Schnittstelle sind und es sich um eine Reihe überladener Funktionen handelt, die nicht rein virtuell sind. Wenn sie rein virtuell wären, könnte man immer noch auf dasselbe Problem stoßen, wie unten beschrieben, jedoch niedriger in der Klassenhierarchie.
class Engine
{
public:
virtual void SetState( int var, bool val ) {/*some implementation*/}
virtual void SetState( int var, int val ) {/*some implementation*/}
};
Nehmen wir nun an, Sie möchten eine abgeleitete Klasse erstellen und müssen nur für die Methode eine neue Implementierung bereitstellen, die zwei Ints als Argumente verwendet.
class MyTurbochargedV8 : public Engine
{
public:
// To prevent SetState( int var, bool val ) from the base class,
// from being hidden by the new implementation of the other overload (below),
// you have to put using declaration in the derived class
using Engine::SetState;
void SetState( int var, int val ) {/*new implementation*/}
};
Wenn Sie vergessen haben, die using-Deklaration in die abgeleitete Klasse einzufügen (oder die zweite Überladung neu zu definieren), können im folgenden Szenario Probleme auftreten.
MyTurbochargedV8* myV8 = new MyTurbochargedV8();
myV8->SetState(5, true);
Wenn Sie das Verstecken der Engine
Mitglieder nicht verhindert haben, lautet die Aussage:
myV8->SetState(5, true);
nennen würde void SetState( int var, int val )
von der abgeleiteten Klasse, die Umwandlung true
zu int
.
Wenn die Schnittstelle nicht virtuell ist und die virtuelle Implementierung nicht öffentlich ist, wie in Ihrem Beispiel, hat der Autor der abgeleiteten Klasse ein Problem weniger zu denken und kann einfach schreiben
class MyTurbochargedV8 : public Engine
{
private:
void SetStateInt(int var, int val ) {/*new implementation*/}
};