C++虚继承及其它特性
一、其它特性
1、冲突
示例:
#include <iostream>
using namespace std;
class A
{
public:
	int x;
	void print()
	{
		cout << "调用类A的print()函数.\n";
		cout << "x=" << x << endl;
	}
};
class B
{
public:
	int y;
	void print()
	{
		cout << "调用类B的print()函数.\n";
		cout << "y=" << y << endl;
	}
};
class C:public A,public B
{
public:
	int y;  // 类B的和类C均有y的数据成员	
};
int main()
{
	C c1;
	c1.x = 100;
	c1.y = 200;  // 未指明的情况下,给派生类中的y赋值
	c1.B::y = 300; // 给基类B的y赋值
	c1.A::print();
	c1.B::print();
	cout << "y=" << c1.y << endl;  // 输出派生类中的y的值
	cout << "y=" << c1.B::y << endl; // 输出基类B中的y的值
	return 0;
}

2、支配原则
当派生类中新增加的数据或函数与基类中原有的同名时,若不加限制,则优先调用派生类中的成员。
3、基类与对象成员
       任一基类在派生类中只能继承一次,否则,会造成成员名的冲突;
        若在派生类中,确实要有二个以上基类的成员,则可用基类的二个对象作为派生类的成员。
        把一个类作为派生类的基类或把一个类的对象作为一个类的成员,在使用上是有区别的:在派生类中可直接使用基类的成员(访问权限允许的话),但要使用对象成员的成员时,必须在对象名后加上成员运算符“.”和成员名。
示例:
class Derived {
private:
    Base1 b1; // Base1 的对象
    Base2 b2; // Base2 的对象
public:
    void show() {
        b1.display(); // 使用对象调用 Base1 的 display()
        b2.display(); // 使用对象调用 Base2 的 display()
    }
};
4、赋值兼容规则
可以将派生类对象的值赋给基类对象。反之不行。只是将从基类继承来的成员赋值。
-  可以将一个派生类对象的地址赋给基类的指针变量。 
-  basep只能引用从基类继承来的成员。 
二、虚继承
类B 是类A的派生类
类C 是类A的派生类
类D 是类B和类C的派生类 这样,类D中就有两份类A的拷贝

        这种同一个公共的基类在派生类中产生多个拷贝,不仅多占用了存储空间,而且可能会造成多个拷贝中的数据不一致和模糊的引用。
在多重派生的过程中,若使公共基类在派生类中只有一个拷贝,则可将这种基类说明为虚基类。在派生类的定义中,只要在基类的类名前加上关键字virtual,就可以将基类说明为虚基类。
由虚基类派生出的对象初始化时,直接调用虚基类的构造函数。因此,若将一个类定义为虚基类,则一定有正确的构造函数可供所有派生类调用。
再次强调,用虚基类进行多重派生时,若虚基类没有缺省的构造函数,则在每一个派生类的构造函数中都必须有对虚基类构造函数的调用 (且首先调用)。
示例:
#include <iostream>
using namespace std;
class A {
public:
	int x;
	A(int a = 0)
	{
		cout << "调用类A:构造函数." << endl;
		x = a;
	}
};
class B : virtual public A {
public:
	int y;
	B(int a = 0, int b = 0) :A(a) {
		cout << "调用类B:构造函数." << endl;
		y = b;
	}
};
class C :virtual public A {
public:
	int z;
	C(int a = 0, int c = 0) :A(a) {
		cout << "调用类C:构造函数." << endl;
		z = c;
	}
};
class D :public B, public C
{
public:
	int dx;
	D(int a1, int b, int c, int d, int a2) :B(a1, b), C(a2, c)
	{
		cout << "调用类D:构造函数." << endl;
		dx = d;
	}
};
int main()
{
	D obj(100, 200, 300, 400, 500);
	cout << "\nobj.x=" << obj.x << endl;
	obj.x = 20000;
	cout << obj.x << endl;
	cout << obj.y << endl;
	return 0;
}
