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;
}