总结:什么是封装
1.数据和方法放到一起,把想给你访问的定义为公有,不想给你访问的定义为私有或保护。
2.一个类型放到另一个类型里面,通过typedef成员函数调整,封装另一个全新的类型。
1.友元关系不能继承
Display是Person的友元函数,可以访问Person的保护和私有。但Display不是Student的友元,不可以访问Student的保护和私有。
解决方案是给Student也来一个友元声明。
补充:
父类的成员变量被派生类继承后,父类和派生类的成员变量就没有关系了,各自玩各自的。
但静态成员变量例外,它始终都只有一份,即属于父类,也属于派生类。
静态成员变量可用于统计父类及其派生类对象一共有多少个:
因为派生类的构造,拷贝构造需要调用父类的构造,拷贝构造。
2.单继承和多继承
单继承:
多继承:
大坑:
有多继承就会出现菱形继承,这样,Person的信息就会被继承两次。
问题:
1.数据冗余。
2.二义性。(访问不明确)。
二义性的问题可以用域作用限定符来解决,但是数据冗余仍然无法解决。
2.1虚继承
解决菱形继承更好的方式:虚继承
在Student和Teacher继承Person时,加一个virtual。
3.多继承中的直接继承模型和虚拟继承模型
直接继承中,对象B中存了_a,_b。C中存了_a,_c。d中存了_d。
虚拟继承中,对象B中存了_b和一个地址(其中记录了B与A之间的距离,也叫偏移量),C也是一样,d中存了_d。
为什么要这样设计,多态会讲。(主要是为了切片的时候方便找到_a)。
多继承时的指针偏移:
在派生类地址给基类指针赋值时,会发生切片,这时pb和pc的值不一样,它们找到它们所存的地址中的偏移量,从而找到_a。
初始化循序:
单继承:基类在前,派生类在后。
多继承:先继承的在前,后继承的在后。
类和对象中:先声明的先初始化,后声明的后初始化。因为声明的顺序是在内存中存的顺序。
总结:实践中可以设计多继承,但切记不要设计菱形继承,因为太复杂,容易出各种问题。
4.提问:(需要知道的,面试可能会问到)
1.C++有多继承,为什么Java没有?
答:根据语言的发展历史,C++早于Java,C++祖师爷也没想到多继承那么复杂。C++2.0提出了多继承,到C++3.0才给出虚继承和解决二义性问题。而Java看到C++的多继承那么复杂故取消多继承!
2.多继承的问题是什么?
答:多继承本身没啥问题,但允许多继承就间接允许菱形继承,菱形继承有问题。
3.菱形继承的问题?如何解决?
答:菱形继承的问题:数据冗余,二义性。如何解决:虚继承
4.从底层角度如何看待数据冗余和二义性?
虚继承后,重复继承的那个类叫做虚基类,虚基类在内存中放在最后面,变成公共的类然后通过偏移量计算虚基类的位置。
5.多用组和,少用继承
5.2组合与继承的深度理解
学生是一个人,就用继承。狗是动物,也用继承。汽车中有轮胎,这里用组合。
可以说栈中有链表,也可以说栈是一个特殊的链表,可以用继承也可以用组合,但为保证低耦合,高内聚,尽量用组合。