Chinaunix首页 | 论坛 | 博客
  • 博客访问: 328888
  • 博文数量: 79
  • 博客积分: 2466
  • 博客等级: 大尉
  • 技术积分: 880
  • 用 户 组: 普通用户
  • 注册时间: 2006-02-07 16:47
文章分类

全部博文(79)

文章存档

2014年(3)

2012年(7)

2011年(14)

2010年(2)

2009年(2)

2008年(2)

2007年(18)

2006年(31)

分类: C/C++

2011-08-21 21:20:17

当代码调用某类的成员函数时,下面三件事依次发生:

首先,编译器查找这个函数名字;编译器查找名为指定名字的函数时,并不在意访问权限和参数类型是否匹配,它只是在“最接近”的那个范围内查找所有名字能匹配的函数。仅当函数在“最接近”的那个范围内没找到任何一个名字能与该调用匹配的函数,才会“向外”退一层,在更广的范围内重复上述查找(比如从派生类“退”到基类,或者从某名字空间“退”到全局空间)。如果退到无路可退还是没有找到指定名字的函数,这就是个编译错误。如果在任何一层找到了至少一个名字能匹配的函数,查找过程停止(注意,更“外层”即使还有更多指定名字的函数定义,编译器也不会考虑它们了)。

第二,重载裁决。编译器从所有符合条件的候选函数中,按照参数类型匹配关系,选择最佳匹配;

第三,编译器检查调用代码是否有权访问最佳匹配的函数。

函数调用到底对应到哪一个函数体,我们经常发生误解。误解的根源主要不是在那些复杂的名字查找和重载裁决规则,误解的根源主要在于对上述三个依次进行的步骤不清楚。

看例子:

#include

void f(double) { }

class B {
public:
    void f(double) { }
};

class D: public B {
    void f(double) { }
public:
    void f(int) { }
};

int
main() {
    D d;
    d.f(12.3);
}


编译得到的错误信息:
main.cpp: In function `int main()':
main.cpp:13: error: `void D::f(double)' is private
main.cpp:21: error: within this context

编译过程到底发生了什么?为什么得到那些错误信息?

第一步:编译器查找函数名字f。因为我们在调用D的实例上的方法,编译器从D的范围开始查找,马上找到D::f(int)和D::f(double)。关键来了:查找过程到此停止!对于更“外层”(此处即基类B,以及全局域)中定义的f,编译器不会考虑在内了!
第二步:选择最佳匹配。这里有两个候选者,那么它们能匹配吗?D::f(double)当然是直接的最佳匹配。
第三步:检查访问权限。D::f(double)是私有成员,编译出错。注意:这里虽然D::f(int)通过一个合法的隐式转换也能匹配(这个隐式转换如果发生,会有编译警告),而且访问权限也没问题,但这一切都没用了!因为上一步的重载函数裁决中不考虑访问权限!一旦在第二步中确定具体要调用哪一个实现,其他被舍弃的重载版本就都不会再被考虑了!

所以出现了上述这个看起来十分“古怪”的例子:三个在不同位置定义的f(double),居然没有一个能让d.f(12.3)这个调用正常完成,而引起了编译错误。

本文内容来自《Exceptional C++》和《C++ Common Knowledge》相关章节
阅读(739) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~