导航网站怎么建,电子商务的概念和特点是什么,淮北市建网站,wordpress简易教程1. 虚基类介绍
多继承时很容易产生命名冲突#xff0c;即使我们很小心地将所有类中的成员变量和成员函数都命名为不同的名字#xff0c;命名冲突依然有可能发生#xff0c;比如非常经典的菱形继承层次。如下图所示#xff1a; 类A派生出类B和类C#xff0c;类D继承自类B和…1. 虚基类介绍
多继承时很容易产生命名冲突即使我们很小心地将所有类中的成员变量和成员函数都命名为不同的名字命名冲突依然有可能发生比如非常经典的菱形继承层次。如下图所示 类A派生出类B和类C类D继承自类B和类C这个时候类A中的成员变量和成员函数继承到类D中变成了两份一份来自 A--B--D 这一路另一份来自 A--C--D 这一条路。
在一个派生类中保留间接基类的多份同名成员虽然可以在不同的成员变量中分别存放不同的数据但大多数情况下这是多余的因为保留多份成员变量不仅占用较多的存储空间还容易产生命名冲突而且很少有这样的需求。
为了解决这个问题C提供了虚基类使得在派生类中只保留间接基类的一份成员。
声明虚基类只需要在继承方式前面加上 virtual 关键字请看下面的例子
#include iostream
using namespace std;class A {
protected:int a;
public:A(int a) : a(a) {}
};class B : virtual public A {
protected:int b;
public:B(int a, int b) : A(a), b(b) {}
};class C : virtual public A {
protected:int c;
public:C(int a, int c) : A(a), c(c) {}
};class D : virtual public B, virtual public C {
private:int d;
public:D(int a, int b, int c, int d) : A(a), B(a, b), C(a, c), d(d) {}void display();
};void D::display()
{cout a a endl;cout b b endl;cout c c endl;cout d d endl;
}int main()
{(new D(1, 2, 3, 4))-display();return 0;
}
输出结果 本例中我们使用了虚基类在派生类D中只有一份成员变量 a 的拷贝所以在 display() 函数中可以直接访问 a而不用加类名和域解析符。
请注意派生类D的构造函数与以往的用法有所不同。以往在派生类的构造函数中只需负责对其直接基类初始化再由其直接基类负责对间接基类初始化。现在由于虚基类在派生类中只有一份成员变量所以对这份成员变量的初始化必须由派生类直接给出。如果不由最后的派生类直接对虚基类初始化而由虚基类的直接派生类如类B和类C对虚基类初始化就有可能由于在类B和类C的构造函数中对虚基类给出不同的初始化参数而产生矛盾。所以规定在最后的派生类中不仅要负责对其直接基类进行初始化还要负责对虚基类初始化。
有的读者会提出类D的构造函数通过初始化表调了虚基类的构造函数A而类B和类C的构造函数也通过初始化表调用了虚基类的构造函数A这样虚基类的构造函数岂非被调用了3次大家不必过虑C编译系统只执行最后的派生类对虚基类的构造函数的调用而忽略虚基类的其他派生类如类B和类C对虚基类的构造函数的调用这就保证了虚基类的数据成员不会被多次初始化。
最后请注意为了保证虚基类在派生类中只继承一次应当在该基类的所有直接派生类中声明为虚基类否则仍然会出现对基类的多次继承。