La domanda nell'argomento suggerisce una confusione piuttosto comune. La confusione è abbastanza comune, che le FAQ del C ++ hanno difeso a lungo l'uso dei virtual privati, perché la confusione sembrava essere una cosa negativa.
Quindi, per eliminare prima la confusione: Sì, le funzioni virtuali private possono essere ignorate nelle classi derivate. I metodi delle classi derivate non possono chiamare funzioni virtuali dalla classe base, ma possono fornire la propria implementazione per loro. Secondo Herb Sutter, avendo un'interfaccia pubblica non virtuale nella classe base e un'implementazione privata che può essere personalizzata nelle classi derivate, consente una migliore "separazione delle specifiche dell'interfaccia dalle specifiche del comportamento personalizzabile dell'implementazione". Puoi leggere di più a riguardo nel suo articolo "Virtuality" .
C'è comunque un'altra cosa interessante nel codice che hai presentato, che merita più attenzione, secondo me. L'interfaccia pubblica è costituita da un insieme di funzioni non virtuali sovraccaricate e tali funzioni chiamano funzioni virtuali non pubbliche e non sovraccaricate. Come al solito nel mondo C ++ è un linguaggio, ha un nome e ovviamente è utile. Il nome è (sorpresa, sorpresa!)
"Virtual non sovraccarichi pubblici Chiamate virtuali non sovraccarichi protette"
Aiuta a gestire correttamente la regola dei nascondigli . Puoi leggere di più qui , ma cercherò di spiegarlo a breve.
Immagina che le funzioni virtuali della Engine
classe siano anche la sua interfaccia ed è un insieme di funzioni sovraccariche che non è puro virtuale. Se fossero puramente virtuali, si potrebbe ancora riscontrare lo stesso problema, come descritto di seguito, ma inferiore nella gerarchia di classi.
class Engine
{
public:
virtual void SetState( int var, bool val ) {/*some implementation*/}
virtual void SetState( int var, int val ) {/*some implementation*/}
};
Ora supponiamo che tu voglia creare una classe derivata e devi fornire una nuova implementazione solo per il metodo, che accetta due ints come argomenti.
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*/}
};
Se hai dimenticato di inserire la dichiarazione di utilizzo nella classe derivata (o di ridefinire il secondo sovraccarico), potresti avere dei problemi nello scenario seguente.
MyTurbochargedV8* myV8 = new MyTurbochargedV8();
myV8->SetState(5, true);
Se non hai impedito il nascondimento dei Engine
membri, la dichiarazione:
myV8->SetState(5, true);
chiamerebbe void SetState( int var, int val )
dalla classe derivata, convertendosi true
in int
.
Se l'interfaccia non è virtuale e l'implementazione virtuale non è pubblica, come nel tuo esempio, l'autore della classe derivata ha un problema in meno a cui pensare e può semplicemente scrivere
class MyTurbochargedV8 : public Engine
{
private:
void SetStateInt(int var, int val ) {/*new implementation*/}
};