1.下级别的类即具有上级别类的所有性质同时也具有自己的特性
2.那么在定义这些下级别的类的时候我们就可以用上继承技术,减少重复的代码
上图是类与类之间的继承方法
进行了继承之后,A类的花括号的内容都会被自动放入B类的花括号中
继承技术的语法:
第一部分 --- 继承方式
继承方式:
1.公共继承:public
2.保护继承:protected
3.私有继承法:private
1.父类中具有私有权限的成员属性能够被子类继承,但是子类无法访问
隐藏的意思就是无法访问
2.如果是公共继承方式,那么父类中的成员属性继承到子类中之后,它们的访问权限都不发生改变
(public依然是public,protected依然是procted)
3.如果是保护继承方式,那么父类中的成员属性继承到子类中之后,它们的访问权限都会变为procted权限 (public变成procted,protected依然是procted)
4.如果是私有继承方式,那么父类中的成员属性继承到子类中之后,它们的访问权限都会变为private权限 (public变成private,protected变成private)
第二部分 --- 继承中的对象模型
1.从一个问题开始:
子类从父类中继承过来的成员属性是属于子类的还是属于父类的呢?
--- 继承就相当于将父类中的部分数据拷贝一份给自己,所以继承的数据是属于子类的
2.子类从父类中继承成员属性的时候,会将父类中所有的非静态成员属性(无论什么权限)都继承下来
3.父类中的私有成员属性被编译器隐藏了,我们访问不到,但是确实被我们继承了。
cl /d1 --- 要注意一个是字母l ,一个是数字1 --- 而且cl后面要跟一个空格
第三部分 --- 继承中的构造和析构顺序![](https://img-blog.csdnimg.cn/7914aa26d96b415b920b36aed8856e3f.png)
1.在我们创建子类的时候,第一个进行的步骤是继承 --- 而继承的第一步则是创建一个父类
所以在我们创建子类的时候先调用父类的构造函数,创建完父类之后会开始创建子类,所以第二步是调用子类的构造函数
2.析构的顺序与构造的顺序相反,所以析构的时候:先析构子类,然后再析构父类
第四部分 --- 继承同名成员处理方式![](https://img-blog.csdnimg.cn/356cca10b2d44598bcb6919fa736814c.png)
上面的两种访问方式都是通过子对象访问时的方式
1.通过子对象访问父类中的成员变量的话 --- 关键是要加上作用域 --- 在点操作符后面加上作用域告诉编译器这个是父类的成员对象 --- 作用域写法 : 成员属性所属的类的类名 :: 成员属性
2.子类继承父类的时候继承的是父类的非静态成员 --- 也就是说继承数据包括父类的非静态成员变量和非静态成员函数
3.如果子类和父类中有同名的成员函数时,我们该如何通过子对象调用父类中同名函数?又该如何通过子对象调用子类中的同名函数?
4.解答第3点:
和调用同名成员变量一样,关键点都是加作用域
5.如果子类和父类中没有同名成员的话,子对象可以通过点操作符直接访问父类中的成员,而不需要加作用域 --- 比如父类中有成员变量b和a,子类继承后又自己加了一个变量a
如果通过子对象访问父类的成员变量b的话 --- 由于子类中没有同名变量所以可以直接用点操作符访问 --- 子对象名.b
但是通过子对象访问父类的成员变量a的话 --- 由于子类中有同名变量,所以我们要在点操作符后面加上作用域来让编译器区分变量 --- 对象名.父类类名 :: a
6.
子类中出现和父类同名的成员的时候,编译器会自动将父类中的同名成员给隐藏掉,如果想要访问这些被隐藏的成员的话,就必须加上作用域才行
第五部分 --- 同名静态成员处理 --- 多一种访问方式 -- 通过类名访问
1.关键词和上面的非静态成员一样:加作用域
2.父类的静态成员子类也能够继承
3.静态成员有两种访问方式 --- 一种是通过对象来访问,一种则是直接通过类名来访问(通过类名来访问的本质就是加作用域)
同名静态成员函数的处理和上面的静态成员变量的处理一样
静态成员也符合下面这个原则:
“当子类出现和父类同名的成员的时候(无论静态还是非静态),编译器都会将父类中同名的成员给隐藏起来 --- 也就是说子对象不可以直接通过 对象名 . 成员名的方式直接访问父类中的同名成员,而是得加上作用域后才能访问 --- 对象名 . 父类类名::成员名 ”
“对于父类中的非同名成员,子类可以直接通过 对象名 . 成员名的方式访问 ”
第六部分 --- 多继承语法
第七部分 --- 菱形继承
1.二义性是指当羊驼要调用动物这个基类的数据的时候,它要调用的是羊继承的那部分还是驼继承的那部分 --- 此时就出现了二义性问题,解决这个问题的方法是加作用域来进行区分
2.对第1点的二义性问题更加深入的讨论我们会发现,羊驼只需要一份动物这个基类的数据就行了,它没必要从羊那里继承一份之后再从驼那里又继承一份
3.如何解决第二点中提到的菱形继承的关键问题呢?
答案就是利用虚继承技术来解决这个问题
变为虚继承后,子类继承的基类(父类)变为虚基类
1.vbptr是虚基类指针 ,而虚基类指针会指向一个vbtable
2.vbtable是虚基类表,table是表格的意思
这个就是一个虚基类表,虚基类表中记录的数据是偏移量是子类继承的虚基类位置编号到同一个虚基类的新位置编号之间的编号差
子类可以通过这个偏移量来找到虚基类最新的位置,以此来访问虚基类中的数据
1.虚继承技术:
子类在使用了虚继承技术集成了父类后,并没有直接继承父类的数据,而是继承了一个虚基类指针,这个虚基类指针指向的是一个虚基类表格,这个虚基类表格中填写的是虚基类指针到基类数据的偏移量,子类可以通过这个偏移量找到并访问基类中的数据。
综上:子类采用虚继承技术之后,基类数据只有一份,所有子类要访问基类中的数据都是通过虚基类指针加偏移量来找到并访问基类中的数据的