众所周知,无论派生级别有多深,“虚拟基类子对象”只会被“派生最多”初始化一次对象构造期间的类而不是“中间派生”类的一次以上,“虚拟基础”的这种语义由编译器保证和实现,但是,当我研究其他成员函数时除外“构造函数”,我发现,编译器不会将它们视为构造函数,即它不会阻止多次调用虚基类的成员函数,这里是代码:
class vb
{
public:
void f(){cout << "vb::f"<<endl;}
};
class A: public virtual vb
{
public:
int a;
public:
void f()
{
vb::f();
cout<<"A::f"<<endl;
}
};
class B: public virtual vb
{
public:
int b;
public:
void f()
{
vb::f();
cout<<"B::f"<<endl;
}
};
class C: public A,public B
{
public:
int c;
public:
void f()
{
vb::f();
A::f();
B::f();
cout<<"C::f"<<endl;
}
};
// test example
int main()
{
C a;
a.f();
}
我在Visual Studio 2008中测试了这段代码,结果是:
VB ::˚F
VB ::˚F
A ::˚F
VB ::˚F
B ::˚F
Ç::˚F 但是,所需的结果是:
VB ::˚F
A ::˚F
B ::˚F
ç::˚F
我的问题是:
如何在上述情况下只调用一次vb :: f()?
为什么C ++的实现者不直接从语言层面支持这种语义?
好的,我尽力让自己明白,但是,我不是英国本地人,希望你明白我的意思,谢谢你的回应!
答案 0 :(得分:3)
当多个派生类从同一个类继承virtualy时,在最派生类的对象中只有该类的一个子对象。这意味着它只能初始化一次 - 它由最派生的类完成。
但这只是初始化。但是,这并不意味着只有最派生的类才能访问虚拟基础的成员。
示例中的继承树是这样的:
vb
/ \
A B
\ /
C
虽然没有虚拟继承,但它会是这样的:
vb vb
| |
A B
\ /
C
在任何一种情况下,A
和B
都没有什么特别之处,它们都来自vb
并且可以毫无问题地调用其方法。在第二种情况下,在C
内部,来电vb::f()
不明确且错误。
答案 1 :(得分:2)
className::functionName(...)
进行合格的方法调用,就不会调用覆盖。virtual
继承不创建基类virtual
的成员函数。尝试在任何地方调用f()
,然后再次尝试将f()
中的成员函数vb
更改为
virtual void f(){cout << "vb::f"<<endl;}
。virtual void f() = 0;
答案 2 :(得分:1)
一个方法将被执行的次数被调用。你不能阻止它。而构造函数是一种特殊的方法,它只被称为一次。因此编译器对构造函数有特殊的语义,并且不能为所有方法都有这样的语义。
虚拟基类在这里的作用是允许您从vb::f();
调用class C
而不含歧义。同样,如果vb
中有一些成员变量,它们也只会被初始化一次。
如果您删除虚拟关键字,则无法从vb::f();
那样致电C
。