继承和派生--多继承、菱形继承问题及解决方法
1 多继承基本语法
class 派生类名 : [继承方式] 基类名1 , [继承方式] 基类名2
{
// ....
};
当多继承的两个父类中有同名成员,调用时需要加作用域区分
#include <iostream>
using namespace std;
class Base1
{
public:
void show()
{
cout << "Base1::m_A = " << m_A << endl;
}
int m_A;
};
class Base2
{
public:
void show()
{
cout << "Base2::m_A = " << m_A << endl;
}
int m_A;
};
class Derive : public Base1, public Base2
{
};
int main()
{
Derive derive;
// 当多继承的两个父类中有同名成员,调用时需要加作用域区分
//derive.m_A = 10;
//derive.show();
derive.Base1::m_A = 10;
derive.Base1::show();
derive.Base2::m_A = 20;
derive.Base2::show();
return 0;
}
2 菱形继承问题
两个类有公共的父类和共同的子类 ,发生菱形继承。
菱形继承导致数据有两份,浪费资源.
#include <iostream>
using namespace std;
class A
{
public:
int a;
};
class B1 : public A
{};
class B2 : public A
{};
class C : public B1, public B2
{};
int main()
{
// C类继承了两份A类中的成员a,浪费资源。
C c;
// 必须添加作用域B1:: 否则会有二义性,导致编译失败
c.B1::a = 10; // 第一份a
cout << "c.B1::a = " << c.B1::a << endl;
// 第二份a
cout << "c.B2::a = " << c.B2::a << endl;
return 0;
}
3 菱形继承解决方法
利用虚继承可以解决菱形继承问题
虚继承语法–关键字 virtual
class 派生类名 : virtual [继承方式] 基类名
{
// ....
};
#include <iostream>
using namespace std;
class A
{
public:
int a;
};
// 虚继承
class B1 : virtual public A
{};
class B2 : virtual public A
{};
class C : public B1, public B2
{};
int main()
{
C c;
c.a = 10;
// 此时只有一份a,可以不添加作用域使用唯一的一份a
cout << "c.a = " << c.a << endl;
cout << "c.B1::a = " << c.B1::a << endl;
cout << "c.B2::a = " << c.B2::a << endl;
return 0;
}
4 虚继承内部工作原理
当发生虚继承后,子类中除了继承基类的成员还继承了一个vbptr指针(虚基类指针) 指向的是一个 虚基类表vbtable 。
虚基类表中记录了偏移量,通过偏移量可以找到唯一的一个a.
#include <iostream>
using namespace std;
// 注意要一字节对齐,否则对齐方式会影响sizeof的计算
#pragma pack(1)
class A
{
public:
int a;
}; // sizeof(A) = 4 // 4--int 4字节
// 虚继承
class B1 : virtual public A
{}; // sizeof(B1) = 4 + 8 = 12 // 4--继承了类A的成员变量a,4字节,继承了vbptr指针(虚基类指针)--8字节
class B2 : virtual public A
{}; // sizeof(B2) = 4 + 8 = 12 // 4--继承了类A的成员变量a,4字节,继承了vbptr指针(虚基类指针)--8字节
class C : public B1, public B2
{}; // sizeof(C) = 4+8+8 = 20
// 4--继承了类A的成员变量a(唯一一份a), 8--继承了B1类的vbptr指针(虚基类指针)--8字节, 8--继承了B2类的vbptr指针(虚基类指针)--8字节
int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B1) << endl;
cout << sizeof(B2) << endl;
cout << sizeof(C) << endl;
return 0;
}