菱形继承(钻石继承)
模型:
拿如下代码举例:
class Person { public: string _name; }; class Student :public Person { public: int _num; }; class Teacher :public Person { public: int _id; }; class Graduate :public Student, public Teacher { public: string _majorCourse; }; void test() { Graduate g; //显示指定访问哪个父类的成员 g.Student::_name = "王想"; g.Teacher::_name = "张良"; }
当派生类Graduate继承了基类Student,Teacher后,同样也继承了它们的成员变量,而基类Student,Teacher又都继承了基类Person,都有变量_name,Graduate的对象中就有了两份name成员,这就造成了菱形继承的二义性和冗余问题,编译系统无法判定应该选择哪一个基类中的_name,解决方法之一是指明数据成员的作用域,如上函数void test()中。
接下来细细说明一下:
class A { public: virtual void func1() { cout << "A::func1" << endl; } virtual void func2() { cout << "A::func2" << endl; } int _a; }; class B :public A { public: virtual void func1() { cout << "B::func1" << endl; } virtual void func3() { cout << "B::func3" << endl; } int _b; }; class C :public A { public: virtual void func1() { cout << "C::func1" << endl; } virtual void func4() { cout << "C::func4" << endl; } int _c; }; class D :public B, public C { public: virtual void func1() { cout << "D::func1" << endl; } virtual void func5() { cout << "D::func5" << endl; } int _d; }; typedef void(*v_func)(); void printvtable(int* vtable) { printf("vtable:0x%p\n", vtable); int** ppvtable = (int**)vtable; for (size_t i = 0; ppvtable[i] != 0; ++i) { printf("vtable[%u]:0x%p->", i, ppvtable[i]); v_func f = (v_func)ppvtable[i]; f(); } cout << "*********************************" << endl; } int main() { D d; d.B::_a = 1; d._b = 2; d.C::_a = 3; d._c = 4; d._d = 5; cout << sizeof(B) << endl; printvtable(*((int**)&d)); printvtable(*((int**)((char*)&d + sizeof(B)))); system("pause"); return 0; }菱形继承的动态模型:
在以上的方法,在派生类对象名后增加直接基类名,避免了二义性,但是它保留多份数据成员的拷贝,不仅占用较多的存储空间,还增加了访问成员的困难,因此我们还有另一种方法可以解决菱形继承的二义性和冗余问题,这里我们引入虚继承,虚继承解决了在菱形继承体系里子类对象包含多份父类对象的数据冗余和浪费空间的问题。
虚继承的作用:在继承间接共同基类时只保留一份成员。
实现方法:在该基类的所有直接派生类声明为虚基类,如下图所示。
代码实现:
class A { public: virtual void func1() { cout << "A::func1" << endl; } virtual void func2() { cout << "A::func2" << endl; } int _a; }; class B :virtual public A { public: virtual void func1() { cout << "B::func1" << endl; } virtual void func3() { cout << "B::func3" << endl; } int _b; }; class C :virtual public A { public: virtual void func1() { cout << "C::func1" << endl; } virtual void func4() { cout << "C::func4" << endl; } int _c; }; class D :public B, public C { public: virtual void func1() { cout << "D::func1" << endl; } virtual void func5() { cout << "D::func5" << endl; } int _d; }; typedef void(*v_func)(); void printvtable(int* vtable) { printf("vtable:0x%p\n", vtable); int** ppvtable = (int**)vtable; for (size_t i = 0; ppvtable[i] != 0; ++i) { printf("vtable[%u]:0x%p->", i, ppvtable[i]); v_func f = (v_func)ppvtable[i]; f(); } cout << "*********************************" << endl; } int main() { D d; d._a = 1; d._b = 2; d._c = 3; d._d = 4; cout << sizeof(B) << endl; printvtable(*((int**)&d)); printvtable(*((int**)((char*)&d + sizeof(B)-sizeof(A)))); printvtable(*((int**)((char*)&d + sizeof(D) - sizeof(A)))); system("pause"); return 0; } 动态模型分析:
1.多重继承复杂,程序的编写、调试和维护都变得更加困难,⼀般不要用。 2.定义菱形结构的虚继承体系结构,因为虚继承体系解决数据冗余问题也带来了性能上的损耗。