重载解析如何在私有修饰符的上下文中工作?

时间:2014-09-16 07:20:41

标签: c++ inheritance overload-resolution

我无法理解以下C ++代码段的输出。

不应objc.fn()致电A fn(),因为B fn() privateC且不应在fn()中显示{1}}。但答案是:对#include<iostream> using namespace std; class A{ public: void fn() { cout << "1"; } }; class B{ void fn() { cout << "2"; } }; class C: public A, public B {}; int main(){ C objc; objc.fn(); return 0; } 的调用不明确。怎么样?

{{1}}

4 个答案:

答案 0 :(得分:4)

根据书C++ Templates: The Complete Guide附录B.1,

  

在非常高的级别,可以处理对命名函数的调用   以下方式:

     
      
  1. 查找名称以形成初始重载集。

  2.   
  3. 如有必要,可以通过各种方式调整此设置(例如,   发生模板扣除)。

  4.   
  5. 任何与该通话完全不匹配的候选人(即使之后)   考虑隐式转换和默认参数)   从过载集中消除。这导致了一组所谓的   可行的职能候选人。

  6.   
  7. 执行过载分辨率以找到最佳候选者。如果有   是一个,它被选中;否则,电话不明确。

  8.   
  9. 检查所选候选人。例如,如果它是   无法访问私人成员,发布诊断。

  10.   

如您所见,最后检查了访问权限,因此将首先在步骤#4报告the call to fn() is ambiguous

答案 1 :(得分:2)

考虑一下:

class D {
    void fn1() {}
public:
    void fn2() {}
};

int main() {
    D d;
    d.fn2(); // Compiles fine
    d.fn1(); // Error: fn1 is private
}

请注意,d.fn1()的错误大约是fn1私有,而不是fn1在此范围内未知或不可见。出于同样的原因,B::fn确实可以看到C

我们得到此行为是因为编译器对公共成员和私有成员的名称解析相同。只有在名称解析后,可访问性检查才会发挥作用。

您的情况也是如此:您的意思是fn?只有在您回答了该问题之后,编译器才会告诉您是否可以访问fn

答案 2 :(得分:1)

正如我所怀疑的,这段代码提供了一个模糊的引用而且没有编译。由于您已声明两个函数具有相同的签名,编译器不知道要选择哪个函数,在编译时提出投诉。

$ make pru
g++     pru.cc   -o pru
pru.cc: In function ‘int main()’:
pru.cc:15:8: error: request for member ‘fn’ is ambiguous
pru.cc:9:9: error: candidates are: void B::fn()
pru.cc:6:9: error:                 void A::fn()
make: *** [pru] Error 1

我认为你可以选择使用哪个函数,放置A :: fn()选择器。即使像本例中的情况那样,其中一个函数是私有的,你有两个函数可供选择(你可以从B方法内部进行调用,你会得到同样的错误---在那个如果你有两种方法的可见性。)

答案 3 :(得分:0)

@songyuanyao已经给出了正确答案 最后检查访问说明符是由C ++标准委员会设计的

如果不是这样,会发生以下情况:

  • 如果将来修改他们的代码并更改其函数的访问说明符,它可能会破坏依赖类的编译。
  • 更可怕的是,你可能会开始称一个完全不相关的功能,并且会一直无视...... !!

让我们假设访问说明符阻止函数参与重载决策,然后:

class A{
  public:
    void fn() { cout << "1"; }
};
class B{
  void fn() { cout << "2"; }
};
class C: public A, public B {};

int main(){
  C objc;
  objc.fn(); // A::fn() is being invoked
  return 0;
}

现在我们修改代码:

class A{
  void fn() { cout << "1"; }
};
class B{
  public:
    void fn() { cout << "2"; }
};

没有其他任何事情被触及,突然

objc.fn(); // B::fn() is being invoked

你的函数的调用者不知道他的基本功能不再相同了。
这是亵渎!!

为了防止所有此类事故发生,标准委员会做出了这一设计决定。