C++虚基类

在多继承时很容易产生命名冲突问题,如果我们很小心地将所有类中的成员变量及成员函数都命名为不同的名字时,命名冲突依然有可能发生,比如非常经典的菱形继承结构。

所谓菱形继承,举个例子,类 A 派生出类 B 和类 C,类 D 继承自类 B 和类 C,这个时候类 A 中的成员变量和成员函数继承到类 D 中变成了两份,一份来自 A 派生 B 然后派生 D 这一路,另一份来自 A 派生 C 然后派生 D 这一条路。


【例 1】
class A
{
public:
    void setx(int a){x = a;}
    int getx(){return x;}
private:
    int x;
};

class B: public A
{
public:
    void sety(int a){y = a;}
    int gety(){return y;}
private:
    int y;   
};

class C: public A
{
public:
    void setz(int a){z = a;}
    int getz(){return z;}
private:
    int z;
};

class D: public B, public C
{
    //......
};
本例即为典型的菱形继承结构,类 A 中的成员变量及成员函数继承到类 D 中均会产生两份,这样的命名冲突非常的棘手,通过域解析操作符已经无法分清具体的变量了。为此,C++ 提供了虚继承这一方式解决命名冲突问题。虚继承只需要在继承属性前加上 virtual 关键字。

【例 2】
#include <iostream>
using namespace std;

class A
{
public:
    void setx(int a){x = a;}
    int getx(){return x;}
private:
    int x;
};

class B: virtual public A
{
public:
    void sety(int a){y = a;}
    int gety(){return y;}
private:
    int y;   
};

class C: virtual public A
{
public:
    void setz(int a){z = a;}
    int getz(){return z;}
private:
    int z;
};

class D: public B, public C
{
    //......
};

int main()
{
    D test;
    test.setx(10);
    cout<<test.getx()<<endl;
    return 0;
}
在本例中,类 B 和类 C 都以虚继承的方式继承类 A,如此操作之后,类 D 只会得到一份来自类 A 的数据。主函数中定义了类 D 的对象 test,然后通过该对象调用从类 A 间接继承来的 setx() 和 getx() 成员函数,因为 B 和 C 继承自类 A 采用的是虚继承,故通过 D 调用 setx() 和 getx() 不会有命名冲突问题,因为 D 类只得到了一份 A 的数据。