C++中的名字查找问题解答
副标题#e#
伴侣最近发邮件问我两个问题。内容如下(为了更适合阅读,我做了简朴修改。译者在此基本上又做了修改):
我在C++的多担任上碰着了很大贫苦。
如图1,A、B1和B2为纯抽象类;C从B1、B2多担任,且实现了全部父类的抽象要领。
图1
此刻:
C* p = new C;
p->Method_of_A(); //从B1、B2都能获得被挪用要领,为什么编译器不报“二义性”(ambiguity)错误呢?
而按图2布局实现担任干系后:
图2
B4* p = new C;
p->Method_of_A();
编译器(VC++)认为有二义性。经调试我发明编译进程中利用了“adjustor thunk”(译者注:详细请参看http://blog.sina.com.cn/u/491874bb010004xq或Stan Lippman的《Inside the C++ Object Model》)。但愿您能解答这两个问题,以辅佐我更好领略C++(更确切的说是VC++)中的MI(多担任)机制。
#p#副标题#e#
好,我们深入研究下这个问题。
上述编译器行为的差别,与担任干系的巨大度、vtable以及adjustor thunk并无直接干系,它其实就是一个名字查找(name lookup)进程(以本例而言,就是查找要领“Method_of_A”)。
在C++中,函数编译时查抄进程如下:
第一步,执行名字查找(name lookup):在挪用类中查找,并生成候选列表;若候选列表为空,再扩大查找范畴(如名字空间内,或父类);如此轮回。假如最终无功效,那么歉仄,就会提示你“名字未能找到”;不然,编译器跳到第二步。
第二步,执行重载分辨(overload resolution):假如第一步获得的候选者个数大于一,编译器将以通报给函数的参数及其范例为依据,实验找到最佳谜底。假如无法据此确定最优者,就会陈诉“存在二义性挪用”。
第三步,可见性查抄(accessibility checking):编译器查抄是否可真正执行挪用(好比,被挪用函数是否是私有的)。
总而言之一句话,上述三个进程,都实现于工具的静态范例基本上,与实例无关。
问题1:
C* p = new C;
p->Method_of_A();
名字查找就只会在C中举办,基础不会到达A,实际就是直接挪用C::Method_of_A.
而在问题2中:
B4* p = new C;
p->Method_of_A();
利用的工具范例是B4,而B4自己没有提供Method_of_A,因此会到其父类B1、B2中查找,功效找到两个,且不能通过重载分辨实现优化,因此陈诉存在二义性。