在c ++中使用带私有继承的声明的意外行为

时间:2014-09-24 16:54:45

标签: c++ inheritance

考虑这个小例子:

#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;
}

使用g ++ 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()在这里可见

  • 如何让编译器只看到A :: foo()而不改变A,B或C的公共接口?

3 个答案:

答案 0 :(得分:6)

1)在名称查找过程中,辅助功能被忽略:如果该成员是公共的,私有的还是受保护的,则无关紧要:所有这些都被同等考虑,这就是为什么{ {1}}和A::fooB::foo内不明确。

C ++标准第3.4节[basic.lookup]:

  

访问规则(第11条)仅在名称查找和功能重载解析(如果适用)成功后才被视为

2)只需将其纳入D

范围内即可
D

答案 1 :(得分:4)

  

为什么B::foo()在这里可见

访问限制不会影响名称查找期间名称的可见性;只有在查找找到明确的匹配后才会检查它们。

  

如何让编译器只看到A :: foo()而不改变A,B或C的公共接口?

using C::foo;添加到D。这隐藏了基类中同名的任何声明,因此D中只能看到那个重载。

或者,限定函数调用:myD.C::foo()

答案 2 :(得分:0)

我不确定为什么会发生冲突。值得庆幸的是,它很容易解决:

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