C++继承
C++继承
本节介绍C++的继承和多态的语法
继承方法
一图解
继承中的对象模型
一句话,在继承中,父类的私有成员只是被隐藏了,占存储空间,还是会被继承下去。
1 | class Base{ |
构造和析构的顺序
构造和析构的顺序,先构造父类,再构造子类;先析构子类,最后再析构父类
同名成员处理
当子类和父类出现同名的成员时:
若访问子类同名成员,直接访问即可;若访问父类同名成员,需要加作用域。
1 | class Base{ |
子父类同名函数调用也是同理,但需要注意的是:
当子类中出现与父类同名的成员函数时,子类的同名成员会隐藏掉父类中所有的同名成员函数(各种重载函数),如果想访问到父类中被隐藏的同名成员函数,需要加作用域(作用域原理同同名成员变量)
同名静态成员处理方式
静态成员和非静态成员出现同名,处理方式一致
若访问子类同名成员,直接访问即可;若访问父类同名成员,需要加作用域。
静态成员能够通过类名访问,详细语法在之前的CPP类的基础中的静态成员已经提及过,——->传送门
(类名: :成员名,来访问静态成员)
多继承语法
C++允许一个类继承多个类
语法:
1 | class 子类 : 继承方式 父类1 , 继承方式 父类2 ... |
多继承可能会引发父类中有同名成员出现,需要加作用域区分
(C++实际开发中不建议使用多继承)
总而言之,多继承中如果父类中出现了同名情况,子类使用时候要加作用域加以区分
菱形继承
菱形继承概念
两个派生类继承同一个基类,某个类同时继承这两个派生类,这种继承称为菱形继承,又称钻石继承。
菱形继承问题
举个例子:
在这张图里面,羊继承了动物的数据,同意驼也继承了一份同样的数据,当羊驼使用数据时,就会产生二义性,解决这个问题的关键在于羊驼取动物的数据时,只从羊或者驼中之一取一份。
1 | class A{ |
观察这个代码,虽然可以通过多继承的作用域加以区分,两个父类相同的数据,但是这样会在实际开发中产生歧义,浪费存储空间,如例子中的羊驼(Bc)的年龄是继承18还是28呢?
实际上,也应该是,这份数据,我们只要有一份就可以。
解决菱形继承
利用虚继承,解决菱形继承的问题
继承之前加上关键字virtual,变为虚继承
在这个例子中,A类称为 虚基类
1 | class A{ |
应用虚继承后,age只有一份。在上面代码的例子中,age先后被赋值为18,28,最后再被改为38,数据只有一份。虚基础是怎么实现只继承一份数据的?其实是用了虚基类指针和虚基类表
虚基础原理
在这张表中,ST从S和T类中继承了vbptr(virtual base pointer)虚基类指针,然后只有一份从虚基类(A)继承的值age。
vbptr指向vbtable(虚基类表),在这个例子中S的vbptr指向的vbtable里的偏移量为8,从vbptr地址处偏移8就能取到age的值,同理,T的vbptr指向的vbtable里的偏移量为4,从该vbptr地址处偏移4就同样能取到age的值,age的值唯一且是共享。