Подтвердить что ты не робот

Изменение режима доступа к функциям в производном классе

Рассмотрим следующий фрагмент:

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.
}

Является ли это законным С++? "This" изменяет режим доступа к виртуальной функции в производном классе.

4b9b3361

Ответ 1

Да, изменение режима доступа в производных классах является законным.

Это похожее в форме, но другое в намерении не виртуальный интерфейс идиома. Некоторое обоснование дано здесь:

Дело в том, что существуют виртуальные функции для настройки; если они также не должны быть вызваны непосредственно из кода производных классов, нет необходимости когда-либо делать что-либо, кроме частных.

Что касается того, почему вы на самом деле делаете что-то public в базе, но private в производном без private или protected наследование выходит за рамки меня.

Ответ 2

Это законный С++, §11.6/1 говорит:

Доступ проверяется в точке вызова используя тип используемого выражения для обозначения объекта, для которого функция-член называется (B * в пример выше). Доступ к член в классе, в котором он был определен (D в примере выше), вообще не известно.

Как вы заметили, Child::Foo(), таким образом, все еще доступен через базовый класс, который в большинстве случаев нежелателен:

 Child* c = new Child;
 Base* b = c;
 c->Foo(); // doesn't work, Child::Foo() is private
 b->Foo(); // works, calls Child::Foo()

В основном, декларация, на которую вы ссылаетесь в выражении, определяет режим доступа, но виртуальные функции подрывают это как другую функцию, тогда именованный может быть фактически вызван.

Ответ 3

Это совершенно законный С++. Вы просто определяете новый метод в классе Child.

Теперь он делает то, что вы хотите, чтобы другой вопрос. Я считаю, что режим доступа не является частью сигнатуры метода, а это значит, что вызов виртуального метода Base Foo в конечном итоге вызывает метод Child Foo.

Итак, вот вывод: это легальный С++, и он работает так, как вы ожидали.

Я не принимаю во внимание строку child.Foo();, которая не может работать, потому что нет сомнений в том, что она пытается получить доступ к методу Child private Foo().

Ответ 4

Кажется, компилируется и вызывается правильный метод.

Помните, что спецификаторы доступа предназначены для помощи дисциплинированному программисту, а не для предотвращения любых попыток обойти его любой ценой.

В этом конкретном случае у ребенка нет бизнеса, делающего переопределенную виртуальную функцию закрытой: не предполагается ли реализовать публичный интерфейс базы, поэтому имеет место отношение "is-a"? (Если вы не использовали публичное наследование, что означает "Ребенок - это база", трюк не будет работать.)