Питання в темі припускають досить поширену плутанину. Плутанина досить поширена, що C ++ FAQ досить довго виступали проти використання приватних віртуалів, тому що плутанина здавалася поганою справою.
Тож, щоб спочатку позбутися від плутанини: Так, приватні віртуальні функції можна переоминути у похідних класах. Методи похідних класів не можуть викликати віртуальні функції з базового класу, але вони можуть забезпечити їх власну реалізацію. За словами Герба Саттера, наявність публічного невіртуального інтерфейсу в базовому класі та приватна реалізація, яку можна налаштувати у похідних класах, дозволяє краще "відокремити специфікацію інтерфейсу від специфікації налаштованої поведінки реалізації". Детальніше про це ви можете прочитати в його статті "Віртуальність" .
Однак у кодексі, який ви подали, є ще одна цікава річ, яка, на мою думку, заслуговує на дещо більше уваги. Загальнодоступний інтерфейс складається з набору перевантажених невіртуальних функцій, і ці функції називають непублічними, не перевантаженими віртуальними функціями. Як зазвичай у світі С ++, це ідіома, вона має назву і, звичайно, корисна. Назва (сюрприз, сюрприз!)
"Загальнодоступні перевантажені невіртуальні виклики, захищені неперевантаженими віртуалами"
Це допомагає правильно керувати правилом приховування . Ви можете прочитати більше про це тут , але я спробую пояснити це найближчим часом.
Уявіть, що віртуальні функції Engine
класу - це також його інтерфейс, і це набір перевантажених функцій, що не є чисто віртуальною. Якби вони були чистими віртуальними, все-таки можна було б зіткнутися з тією ж проблемою, що описана нижче, але нижче в ієрархії класів.
class Engine
{
public:
virtual void SetState( int var, bool val ) {/*some implementation*/}
virtual void SetState( int var, int val ) {/*some implementation*/}
};
Тепер припустимо, що ви хочете створити похідний клас, і вам потрібно надати нову реалізацію лише для методу, який бере два аргументи як аргументи.
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*/}
};
Якщо ви забули поставити використовуючу декларацію у похідний клас (або перевизначити другу перевантаження), ви можете зіткнутися з проблемою у нижченаведеному сценарії.
MyTurbochargedV8* myV8 = new MyTurbochargedV8();
myV8->SetState(5, true);
Якщо ви не перешкодили приховуванню Engine
членів, заява:
myV8->SetState(5, true);
дзвонить void SetState( int var, int val )
із похідного класу, перетворюючись true
на int
.
Якщо інтерфейс не віртуальний і віртуальна реалізація не є загальнодоступною, як у вашому прикладі, у автора похідного класу є одна менша проблема думати і він може просто написати
class MyTurbochargedV8 : public Engine
{
private:
void SetStateInt(int var, int val ) {/*new implementation*/}
};