9.6 名字查找问题

我们已经以子对象举例说明的二义性适用于任何名字,包括函数名。如果一个类有多个直接基类,就可以共享这些基类中那些同名的成员函数,如果要调用这些成员函数中的一个,那么编译器将不知道调用它们之中的哪一个。下面的程序举例将会报告这样一个错误:

9.6 名字查找问题 - 图1

类Bottom已经继承了两个同名的函数(因为名字查寻发生在重载解析之前,所以识别标志是不恰当的),并且没有方法在它们之间进行选择。通常消除二义性调用的方法,是以基类名来限定函数的调用:

9.6 名字查找问题 - 图2

9.6 名字查找问题 - 图3

现在在Bottom的作用域中可以找到名字Left:f,所以完全不用考虑名字Right:f的查找问题。为了介绍Left:f()函数所能提供的更多额外功能,需要实现调用函数Left:f()的Bottom:f()函数。

在一个层次结构中的不同分支上存在的同名函数常常发生冲突。下面的继承层次结构不存在这样的问题:

9.6 名字查找问题 - 图4

程序在这里没有显式调用Right:f()。因为Left:f()是位于层次结构的最高层派生类,所以对b.f()语句的执行将调用Left:f()。为什么呢?现在假设Right不存在,这样就成为一个单一层次结构Top<=Left<=Bottom。在这里可以确定地预期由表达式b.f()调用的函数是Left:f(),因为一般的作用域规则是:一个派生类被认为嵌套在基类的作用域之内。一般情况下,如果类A直接或间接派生自类B,或换句话说,在继承层次结构中类A比类B处于“更高的派生层次”,[1]那么名字A:f就比名字B:f占优势(dominate)。因此,在同名的两个函数之间进行选择时,编译器将选择占优势的那个函数。如果没有占优势的名字,就会产生二义性。

下面的程序更进一步地举例说明了占优势的原则:

9.6 名字查找问题 - 图5

这个层次结构的类图如下:

类A是类B的基类(在这个例子中是直接基类),所以名字B:f比名字A:f占优势。

[1]注意,对这个例子来说虚拟继承是至关重要的。如果Top不是虚基类,将存在多个虚Top子对象,并且二义性还将存在。多重继承的优越性只与虚基类一同存在。