Рассмотрите следующий отрывок:
struct Base
{
virtual ~Base() {}
virtual void Foo() const = 0; // Public
};
class Child : public Base
{
virtual void Foo() const {} // Private
};
int main()
{
Child child;
child.Foo(); // Won't work. Foo is private in this context.
static_cast<Base&> (child).Foo(); // Okay. Foo is public in this context.
}
Этот юридический C ++? Причем «Этот» изменяющийся режим доступа виртуальной функции в производном классе.
Да, изменение режима доступа в производных классах является законным.
Это аналогичное в форме в форме, но различно в намерениях , не виртуальный интерфейс IDIOM. Некоторые обоснование дано здесь :
Точка заключается в том, что существуют виртуальные функции для настройки; Если они также не должны быть вызваны непосредственно из-под известных классов, нет необходимости делать их что-либо, кроме частного.
Поэтому к тому, почему вы на самом деле сделаете что-то
в базе, но частные
в производстве без Private
или защищены
Наследование Отказ
Это совершенно легальный C++. Вы просто определяете новый метод в классе Child.
Теперь он делает то, что вы хотите, это другой вопрос. Я считаю, что режим доступа не является частью сигнатуры метода, что означает, что вызов виртуального метода Base's Foo в конечном итоге делает вызов метода Child's Foo.
Итак, вот вывод: это легальный c++ и он работает так, как вы ожидали.
Я не принимаю во внимание строку child.Foo();
, которая не может работать, так как нет сомнений, что она пытается получить доступ к закрытому методу Child's Foo().
Кажется, что он скомпилировал и вызвал правильный метод.
Помните, что спецификаторы доступа существуют для того, чтобы помочь дисциплинированному программисту, а не для того, чтобы любой ценой обойти его.
В данном конкретном случае, Child не имеет никакого дела, делая переопределенную виртуальную функцию приватной: разве она не должна реализовывать публичный интерфейс Base, так что отношение "есть-а" держится? (Если бы вы не использовали публичное наследование, что означает "Child is a Base", ваш трюк не сработал бы)
.Это законно C ++, §11.6 / 1 говорит:
Доступ проверяется в точке вызова Использование типа используемого выражения обозначить объект, для которого Функция участника называется (B * в Пример выше). Доступ Функция участника в классе, в котором Это было определено (D в примере Выше) в целом не известно.
Как вы уже отмечали, Ребенок :: Foo ()
, таким образом, все еще доступны через базовый класс, который в большинстве случаев нежелательно:
Child* c = new Child;
Base* b = c;
c->Foo(); // doesn't work, Child::Foo() is private
b->Foo(); // works, calls Child::Foo()
в основном, декларация, которую вы ссылаетесь в выражение, диктуют Режим доступа - но виртуальные функции подрывают, что в качестве другой функции, то именованная тонама на самом деле может быть вызвана.