С++ переопределяет частный чистый виртуальный метод как открытый
Почему это происходит?
http://coliru.stacked-crooked.com/a/e1376beff0c157a1
class Base{
private:
virtual void do_run() = 0;
public:
void run(){
do_run();
}
};
class A : public Base {
public:
// uplift ??
virtual void do_run() override {}
};
int main()
{
A a;
a.do_run();
}
Почему я могу переопределить виртуальный метод PRIVATE как открытый?
Ответы
Ответ 1
Согласно https://en.cppreference.com/w/cpp/language/virtual#In_detail, перезапись базовой virtual
функции-члена заботится только о имени функции, параметрах, const/volatile-ness и ref qualifier. Он не заботится о типе возврата, модификаторе доступа или других вещах, о которых вы могли бы подумать.
Связанная ссылка также специально отмечает, что:
База :: vf не должна быть видимой (может быть объявлена частной или унаследованной с использованием частного наследования), которая будет переопределена.
Ничто из того, что я могу найти, явно дает разрешение на это, но правила переопределения не мешают этому. Это разрешено в силу virtual
функций и функций, которые переопределяют существующие и не запрещают этот случай.
Если вы спрашиваете, почему это так, как язык, вам, возможно, придется обратиться в комитет по стандартизации.
Ответ 2
Это поведение предназначено. Если метод является виртуальным, то он должен быть настраиваемым производными классами, независимо от модификатора доступа.
См. Здесь
Ответ 3
Почему я могу переопределить виртуальный метод PRIVATE как общедоступный???
Потому что вы смотрите, что базовый метод является приватным с неправильным углом. B::do_run
- это частные средства, "только члены и друзья этого класса могут его использовать". Чтобы запретить производные классы от переопределения, нам нужен отдельный спецификатор, но мы можем просто сделать его не virtual
. Класс A
с другой стороны позволяет кому-либо позвонить A::do_run()
и это зависит от дизайнера класса A
Таким образом, нет никакого поднятия, как вы видите.
Ответ 4
Обратите внимание, что эта реализация не изменяет способ доступа к базовому классу и конструкцию:
Base& b = a;
b.do_run();
не будет работать.
Я помню, что за этим объясняется некоторое обоснование, описанное более подробно в "Эффективном C++" Скотта Мейерса. Но ключевой практической особенностью является возможность использовать такую гибкость в обратном направлении, чтобы переопределить члены публичного базового класса с частными функциями в производном классе, заставляя клиента использовать базовый класс в качестве интерфейса и не испытывать соблазна напрямую использовать который должен оставаться скрытой реализацией.
Ответ 5
Если намерение состоит в том, чтобы написать частный код для базового класса и предотвратить возможность его переопределения, реализовать частную функцию в базовом классе и объявить его final
, иначе: когда кто-то будет использовать частные виртуальные машины? Часто задаваемые вопросы по ISOCPP.ORG