Почему компилятор C ++ не делает различий между унаследованным public и унаследованным private методом с тем же именем? - PullRequest
6 голосов
/ 26 августа 2011

Я не понимаю, почему компилятор C ++ не примет это:

  class Foo { 
    private: void Baz() { }
  };

  class Bar {
    public: void Baz() { 
  };

  class FooBar : public Foo, public Bar { };

  void main() {
    FooBar fb;
    fb.Baz();
  }

Ошибка, которую выдает gcc:

 request for member ‘Baz’ is ambiguous
 candidates are: void Bar::Baz()
                 void Foo::Baz()

, но разве не очевидно, чтоЯ хочу Bar :: Baz (), так как Foo :: Baz () является частным?Почему компилятор не устраняет неоднозначность здесь?

Ответы [ 5 ]

7 голосов
/ 26 августа 2011

Разрешение имен работает в два этапа. Сначала ищется имя, затем имя проверяется на доступ. Если поиск имени неоднозначен, то доступ никогда не рассматривается.

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

3 голосов
/ 26 августа 2011

Это не очевидно - вы, возможно, хотели вызвать частного участника (если это было возможно).

Формально правила языка говорят, что имя разрешается первым и выбирается лучшая перегрузка.Только после этого проводится проверка доступности.

2 голосов
/ 26 августа 2011

Для того, чтобы это разрешить, необходимо рассмотреть, находитесь ли вы в контексте, позволяющем вам вызывать закрытый метод, или нет.Если бы это было разрешено, то вызов:

fb.Baz()

может иметь совершенно разные функции в зависимости от того, вызываете ли вы его из открытого или частного контекста.И это не совсем соответствует тому, как работает язык.

1 голос
/ 26 августа 2011

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

fb.Bar::Baz()
1 голос
/ 26 августа 2011

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

class Base
{
  virtual void secret_power() { /* innocent default */ }
public:
  void use_me() { secret_power(); }
};

class Derived : public Base
{
  virtual void secret_power() { /* overriding implementation here */ }
};

Теперь для любого Base& вы всегда можете вызвать не виртуальный общедоступный интерфейс use_me(), но ваши производные классы обеспечивают реализацию посредством частного виртуального.

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