2014-09-24 2 views
3

Рассмотрим небольшого примера:неожиданного поведения с использованием декларации с частным наследованием в C++

#include <iostream> 

struct A 
{ 
    void foo() 
    { 
     std::cout << "A::foo" << std::endl; 
    } 
}; 

struct B 
{ 
    void foo() 
    { 
     std::cout << "B::foo" << std::endl; 
    } 
}; 

struct C:private A 
{ 
    using A::foo; 
}; 

struct D:private B, public C 
{ 
}; 

int main() 
{ 

    D myD; 
    myD.foo(); 
    return 0; 
} 

При составлении этого примера с г ++ 4.8.1, я получаю эти ошибки:

prog.cpp: In function ‘int main()’: 
prog.cpp:32:9: error: request for member ‘foo’ is ambiguous 
    myD.foo(); 
     ^
prog.cpp:5:10: note: candidates are: void A::foo() 
    void foo() 
     ^
prog.cpp:5:10: note:     void A::foo() 
prog.cpp:13:10: note:     void B::foo() 
    void foo() 

Я бы подумал, что поиск D :: foo() проигнорировал B :: foo(), потому что B частным образом унаследован от D, и в D. нет объявления using. Я бы подумал, что единственным видимым foo() будет A: : Foo().

Но ясно, что я ошибся, и я неправильно понял аспект декларации using.

Может кто-нибудь объяснить:

  • Почему B :: Foo() виден здесь

  • Как сделать компилятор видеть только :: Foo() без изменения общественных интерфейсов A , B или C?

ответ

6

1) Доступность является игнорируется во имя поиска: не имеет значения, если член является публичным, частным или защищены: все одинаково считается, что почему A::foo и B::foo неоднозначны в пределах D.

C++ стандарт раздел 3.4 [основной.поиск]:

правил доступа (пункт 11) рассматривается только один раз имя поиск и функция разрешение перегрузки (если это применимо) удались

2) Просто привести его в рамки в D:

struct D: private B, public C 
{ 
    using C::foo; 
}; 
0

Я не совсем уверен, почему возникает конфликт. К счастью, хотя, это довольно легко решить:

struct D:private B, public C 
{ 
    using C::foo; 
}; 
4

Почему B::foo() виден здесь

ограничение доступа не влияет на видимость имен во имя поиска; они проверяются только после того, как поиск нашел недвусмысленное совпадение.

Как сделать комплимент видным только A :: foo() без изменения общедоступных интерфейсов A, B или C?

Добавить using C::foo; в D. Это скрывает любые объявления с одинаковым именем в базовых классах, поэтому только одна перегрузка видима в пределах D.

Кроме того, право на вызов функции: myD.C::foo()

Смежные вопросы