Вопрос в теме наводит на мысль о довольно распространенной путанице.Путаница достаточно распространена, и C ++ FAQ долгое время выступали против использования частных виртуальных машин, потому что путаница казалась плохой вещью.
Итак, чтобы сначала избавиться от этой путаницы:Да, частные виртуальные функции могут быть переопределены в производных классах.Методы производных классов не могут вызывать виртуальные функции из базового класса, но они могут предоставить для них собственную реализацию.Согласно Хербу Саттеру, наличие общедоступного не виртуального интерфейса в базовом классе и частной реализации, которую можно настраивать в производных классах, позволяет лучше «отделить спецификацию интерфейса от спецификации настраиваемого поведения реализации».Подробнее об этом вы можете прочитать в его статье «Виртуальность» .
Однако в представленном вами коде есть еще одна интересная вещь, которая, на мой взгляд, заслуживает большего внимания.Открытый интерфейс состоит из набора перегруженных не виртуальных функций, и эти функции вызывают непубличные, не перегруженные виртуальные функции.Как обычно в мире C ++, это идиома, у нее есть имя и, конечно, она полезна.Имя (сюрприз, сюрприз!)
"Общедоступные перегруженные не виртуальные защищенные вызовы незагруженные виртуальные компьютеры"
Помогает правильно управлять правилом сокрытия .Вы можете прочитать больше об этом здесь , но я постараюсь объяснить это в ближайшее время.
Представьте себе, что виртуальные функции класса 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*/}
};
Если вы забыли поместить объявление using в производный класс (или переопределить вторую перегрузку), вы можете столкнуться с проблемами всценарий ниже.
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*/}
};