int ?:
public:
C (int q = 0, int m = 0. int n = 0); B (m, n) { c = q: }
(
):
C类的构造函数只能调用B类的构造函数,而B类的构造函数只能调用A类的构造函数。这里,C类
的构造函数使用值q,并将值m和n传递给B类的构造函数;而B类的构造函数使用值m,并将值n传递
给A类的构造函数。
如果Worker是虚基类,则这种信息自动传递将不起作用。例如,对于下面的MI构造函数:
SingingWaiter (const Worker & wk, int p = 0, int v = Singer: :other)
: Waiter (wk. p), Singer (wk, v) (} // flawed
存在的问题是,自动传递信息时,将通过2条不同的途径(Waiter和Singer)将wk传递给 Worker 对
象。为避免这种冲突,C++在基类是虚拟的时,禁止信息通过中间类自动传递给基类。因此,上述构造函
数将初始化成员 panache和 voice,但wk参数中的信息将不会传递给子对象Waiter。不过,编译器必须在
构造派生对象之前构造基类对象组件;在上述情况下,编译器将使用Worker的默认构造函数。
如果不希望默认构造函数来构造虚基类对象,则需要显式地调用所需的基类构造函数。因此,构造函
数应该是这样:
SingingWaiter (const Worker & wk, int p = 0, int v = Singer :: other)
: Worker (wk) Waiter (wk, p), Singer (wk, v) {]
上述代码将显式地调用构造函数worker(const Worker&)。请注意,这种用法是合法的,对于虚基类,
必须这样做:但对于非虚基类,则是非法的。
警告:如果类有间接虚基类,则除非只需使用该虚基类的默认构造函数,否则必须显式地调用该虚基
类的某个构造函数
14.3.2 哪个方法
除了修改类构造函数规则外,MI通常还要求调整其他代码。假设要在SingingWaiter类中扩展Show()
方法。因为SingingWaiter对象没有新的数据成员,所以可能会认为它只需使用继承的方法即可。这引出了
第一个问题。假设没有在SingingWaiter类中重新定义Show()方法,并试图使用SingingWaiter对象调用继
承的Show()方法:
SingingWaiter newhire ("Elise Hawks", 2005, 6, soprano) :
newhire.Show(): // ambiguous
对于单继承,如果没有重新定义 Show(),则将使用最近祖先中的定义。而在多重继承中,每个直接
祖先都有 个Show(函数,这使得上述调用是二义性的。
警告:多重继承可能导致函数调用的二义性。例如,BadDude 类可能从 Gunslinger 类和 PokerPlayer
类那里继承两个完全不同的Draw()方法。
可以使用作用域解析操作符来澄清编程者的意图:
SingingWaiter newhire ("Elise Hawks". 2005, 6, soprano) :
newhire. Singer: : Show(): // use Singer version
不过,更好的方法是在SingingWaiter中重新定义Show(,并指出要使用哪个Show()。例如,如果希
望 SingingWaiter 对象使用 Singer版本的Show(),则可以这样做:
void SingingWaiter: : Show ()
Singer: :Show():
对于单继承来说,让派生方法调用基类的方法是可以的。例如,假设HeadWaiter类是从Waiter类派生
而来的,则可以使用下面的定义序列,其中每个派生类使用其基类显示信息,并添加自己的信息:
void Worker: : Show() const
cout << "Name: " << fullname << "
":