众所周知,继承是c++中的一个特性,我们今天了解一下c++中单继承 多继承以及菱形继承。
何为继承,继承是面向对象语言中可以使代码复用的一个机制。我们可以保持我们原有类的基础上,扩展一些新的功能,新扩展的类被称为派生类,而原有的类叫做基类。
那么它的用法如下
#include<iostream>
using namespace std;
class A
{
public:
void testfunc()
{}
int _a;
};
class B1 :public A //B1类公有的继承类A,B1类被称为派生类,而A类叫基类
{
public:
int _b;
};
class B2 :public A
{
public:
int _b2;
};
其中在继承的基类前的public为继承方式,一共有public protected private三种继承方式。
类成员/继承方式 | public继承 | protected继承 | private继承 |
基类的public成员 | 派生类的public | 派生类的protected | 派生类的private |
基类的protected成员 | 派生类的protected | 派生类的protected | 派生类的private |
基类的private成员 | 派生类中不可见 | 派生类中不可见 | 派生类中不可见 |
派生类对象可以赋值给基类对象/ 基类指针 /基类引用
#include<iostream>
using namespace std;
class A{
public:
void testfunc()
{}
int _a;
};
class B1 :public A{
public:
int _b;
};
class B2 :public A{
public:
int _b2;
};
class C :public B1, public B2
{
public:
int _c;
};
int main()
{
cout << sizeof(C) << endl;
C d;
C M;
//d._c = 2;
//d._b = 4;
//d.B::_a = 3;
//d.B2::_a = 5;
B2 c = d; //派生类可以赋值给基类的对象
B2 *d = &d; //派生类可以赋值给基类的指针
B2 &m = d; //派生类可以赋值给基类的引用
B2* n = &d;
n = &d;
C* f = (C*)n;//基类的指针可以通过强制类型转换赋值给派生类指针
system("pause");
// M = c; 基类不能给派生类赋值
return 0;
}
这段代码还出现了菱形继承,在说菱形继承之前,我们首先要知道,继承分两种,单继承和多继承。
单继承:就是子类只有一个直接父类。
多继承:子类有两个或以上的直接父类,菱形继承是多继承的一种
菱形继承
什么为菱形继承,比如我们定义了一个类A,然后分别定义两个类B1和B2,这两个类都是类A的派生类,然后我们现在又定义了一个类C,这个类C同时继承了类B1和B2.那么这时会出现什么问题呢,这时,如上图代码所示,其实我们计算一下类C的大小,就会发现sizeof之后大小为20,我们每个类中只定义了一个int的变量,这就说明了,我们类C继承的类B1和B2中都包含了类A的成员变量,于是我们在主函数中如果创建一个类C的对象,然后去给这个对象中包含的父类的A中的成员变量去赋值,其实是不可以的,因为编译器不知道我们调用的是从类B1还是类B2中继承的变量,这就是菱形继承的二义性。当然两份的数据也会导致数据冗余。
二义性问题可以通过显式访问的是哪个父类的成员解决,但是无法解决数据冗余问题。
解决菱形继承问题?
解决菱形继承的办法
虚拟继承就可以解决二义性和数据冗余的问题,即在继承方式前面加virtual,然后在访问的时候,就会有两个指针,被称为虚基表指针,两个表叫虚基表,虚基表中存的偏移量,通过偏移量就可以找到这个值。