Изменение режима доступа к функциям в производном классе - PullRequest
26 голосов
/ 26 января 2010

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

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 ++? «Это» - изменение режима доступа виртуальной функции в производном классе.

Ответы [ 4 ]

21 голосов
/ 26 января 2010

Это законно C ++, §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()

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

15 голосов
/ 26 января 2010

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

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

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

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

5 голосов
/ 26 января 2010

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

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

Итак, вот вывод: это законный c ++, и он работает так, как вы ожидаете.

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

4 голосов
/ 26 января 2010

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...