假设有下面的几个类定义:
[C++] 纯文本查看 复制代码 class A
{
int a;
public:
A(int n = 0) : a(n) {}
...
};
class B: public A
{
int b;
public:
B(int m = 0, int n = 0) : A(n), b(m) {}
...
};
class C : public B
{
int c;
public:
C(int q = 0, int m = 0, int n = 0) : B(m, n), c(q) {}
...
};
上面代码中,几个类的声明与继承都是通常的情况。此时,C 类的构造函数只能调用 B 类的构造函数,而 B 类的构造函数只能调用 A 类的构造函数。这里,有一个信息向上传递的路径:C 类的构造函数将值 m 和 n 传递给 B 类的构造函数;而 B 类的构造函数又将值 n 传递给了 A 类的构造函数。
现在,假设 Worker 为一个虚基类,Singer 与 Waiter 都从其派生,而 SingingWaiter 则继承了 Singer 与 Waiter ,这是多重继承。如果给 Singingwaiter 添加如下一条构造函数:- SingingWaiter(const Worker & wk, int p = 0, int v = other) : Waiter(wk, p), Singer(wk, v) {}
复制代码 在 Worker 为虚基类的这种情况下,上面第一个例子中所演示的信息自动传递将不起作用。假如可以传递,那么将有 Waiter 和 Singer 这两条不同的路径将 wk 传递给 Worker 对象,这样就会引起冲突。因此 C++ 规定,在基类为“虚”时,禁止信息通过中间类自动传递给基类。因此,参数 wk 中的信息不会传递给子对象 Waiter。但是,这么一来会跟一个规定相矛盾:编译器必须在构造对象之前构造基类对象组件。因此,在上述情况下,编译器会先直接跳去执行 Worker 的默认构造函数。
如果我们不希望默认构造函数来构造虚基类的对象,解决的办法是,显式地调用所需的基类构造函数。因此,改写上面的构造函数为:
SingingWaiter(const Worker & wk, int p = 0, int v = other) : Worker(wk), Waiter(wk, p), Singer(wk, v) {}
上述代码将显式地调用虚基类的构造函数 Work(const Work &) 。对于虚基类来说,这种用法是合法的,但对于非虚基类,则是非法的。
总之,如果类有间接虚基类,那么除非只需使用该虚基类的默认构造函数,否则必须显式地调用该虚基类的某个构造函数。
|