成员函数查找[条款24]---《C++必知必会》

调用一个成员函数,涉及三个步骤:第一步,编译器查找函数的名字;第二部,从可用候选者中选择最佳匹配函数;第三步,检查是否具有访问该函数的权限。

#include<iostream>
using namespace std;

class B{
public:
    void f(double para){
    cout<<"B::f"<<para<<endl;
    }
};
class D:public B{
//void f(int para){}; //私有成员,编译main中 d.f(12.3)行,会报错
public: void f(int para){ cout<<"D::f"<<para<<endl; } }; class E:public D{ int f; }; int main() { D d; d.f(12.3); //输出D::f12 E e; e.f(12.3); //错误 return 0; }

分析:

  步骤1:查找函数的名字。因为我们正在调用一个D对象的成员,所以将从D的作用域开始查找并且立即定位到D::f上。

  步骤2:从可用的候选者中选择最佳的匹配函数。我们只有一个候选者D::f(为什么只是一个,往后面看),因此会尝试匹配该函数。可以通过将实参12.3从double转换为int而做到这一点(这是合法的,但通常不是我们想要的,因为那样会丢失精度)。

  步骤3:检查访问权限。我们(可能)会得到一个错误,因为D::f是私有成员。

基类中的哪一个看上去有着更好的匹配、并且可访问的函数f已经无关紧要,因为一旦在内层作用域中找到一个,编译器就不会到外层作用域中继续查找该名字。内层作用域中的名字会隐藏外层作用域中相同的名字。在这一点,C++不同于Java。Java中,内层作用域的方法名字和外层作用域中同名方法属于重载关系。

  实际上,改名字甚至不是一个函数的名字:

class E:public D{
    int f;
};
//...
    E e;
    e.f(12.3); //错误
 

反思:

  在这个例子中,我们得到一个编译器错误,因为在作用域E中查找名字f,结果找到了一个数据成员,而不是成员函数。顺便说一下,这也是建立并遵从简单的命名诸多理由之一。如果数据成员E::f被命名为 f_ 或者 m_f,它就不会隐藏被继承的基类函数 f 了

原文地址:https://www.cnblogs.com/azbane/p/8535129.html