对C ++中的虚拟基类感到困惑

时间:2013-11-17 13:02:53

标签: c++ virtual

众所周知,无论派生级别有多深,“虚拟基类子对象”只会被“派生最多”初始化一次对象构造期间的类而不是“中间派生”类的一次以上,“虚拟基础”的这种语义由编译器保证和实现,但是,当我研究其他成员函数时除外“构造函数”,我发现,编译器不会将它们视为构造函数,即它不会阻止多次调用虚基类的成员函数,这里是代码:

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

我的问题是:

  1. 如何在上述情况下只调用一次vb :: f()?

  2. 为什么C ++的实现者不直接从语言层面支持这种语义?

  3. 好的,我尽力让自己明白,但是,我不是英国本地人,希望你明白我的意思,谢谢你的回应!

3 个答案:

答案 0 :(得分:3)

当多个派生类从同一个类继承virtualy时,在最派生类的对象中只有该类的一个子对象。这意味着它只能初始化一次 - 它由最派生的类完成。

但这只是初始化。但是,这并不意味着只有最派生的类才能访问虚拟基础的成员。

示例中的继承树是这样的:

   vb
  /  \
 A    B
 \   /
   C

虽然没有虚拟继承,但它会是这样的:

vb  vb
 |   |
 A   B
 \   /
   C

在任何一种情况下,AB都没有什么特别之处,它们都来自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