一、继承
1. 继承中的作用域
隐藏规则:
1.在继承体系中基类和派生类都有独立的作用域。
2.派生类和基类中有同名成员,派生类成员将屏蔽基类对同名成员的直接访问,这种情况叫隐藏(在派生类成员函数中,可以使用基类::基类成员显示访问)。

3.如果是成员函数的隐藏,只需要函数名相同就构成隐藏。


4.在实际中继承体系最好不要定义同名成员。
2. 派生类的默认成员函数
. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员,如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用,否则(基类有默认构造函数,就可以不用显示调用)。
这是因为,默认构造函数不用传参可以自动调用,反之,必须要传参才可以调用。 (派生类当中的基类成员看做是一个整体,即自定义类型:基类的类型)



. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。


. 派生类的operator=必须调用基类的operator=完成基类的赋值,需要注意的是派生类的operator=隐藏了基类的operator=,所以需要显示的调用基类的operator=,需要指定基类作用域。


. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。(保证析构时是先子后父的顺序)


. 派生类对象初始化时先调用基类构造再调用派生类构造。
. 派生类对象析构先调用派生类析构再调用基类析构。
在C++中可以实现一个不能被继承的类 :基类构造函数私有化,派生类的构成必须调用基类的构造函数,但是基类的构造函数私有以后,派生类就看不见就不能调用了,那么派生类就不能实例化出对象了(C++98的方法)。


在C++11中新增了一个final关键字,final修改基类,派生类就不能继承了。


3. 继承与友元
友元关系不能继承,也就是说基类友元不能访问派生类私有和保护成员。


解决方法 :Display也变成Student的友元即可。
4. 继承与静态成员
基类定义了static静态成员,则整个继承体系里面只有一个这样的成员,无论派生出多少个派生类,只有一个static成员实例 。因为静态成员不属于任何一个对象。


5. 多继承及其菱形继承的问题
单继承 :一个派生类只有一个直接基类时称这个继承关系为单继承。

多继承 :一个派生类有两个或以上的直接基类时称这个继承关系为多继承,多继承对象在内存中的模型是,先继承的基类在前面,后继承的基类在后面,派生类成员在最后面。

正是因为有了多继承的概念,所以有了菱形继承。那么,什么是菱形继承呢?
菱形继承是多继承的一种特殊情况,菱形继承有数据冗余和二义性的问题,在Assistant的对象中Person成员会有两份。




二义性问题勉强可以解决,但是数据冗余的问题却没有得到解决 。所以有了虚继承。


编译器会把冗余的这部分数据单独拿出来找一个区域存放。
6. I/O库中的菱形虚拟继承


ios继承了ios_base,istream,ostream继承了ios,iostream继承了istream,ostream,虽然也是个菱形继承,但是库里面解决了菱形继承的问题,所以,我们不需要担心。
7. 继承和组合
. public继承是一个is-a的关系。也就是说,每个派生类对象都是一个基类对象。
. 组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象。
. 继承允许你根据基类的实现来定义派生类的实现,这种通过生成派生类的复用通常被称为白箱复用。在继承方式中,基类内部的实现细节对派生类可见,继承一定程度上破坏了基类的封装,基类的改变对派生类有很大的影响,派生类和基类之间的依赖关系很强,耦合度高。
. 对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组装和组合对象来获得 。对象组合要求被组合的对象具有良好定义的接口,这种复用风格叫做黑箱复用,因为对象内部的细节是不可见的,组合类之间没有很强的依赖关系,耦合度低 。优先使用对象组合有助于保持每个类被封装。
. 优先使用组合而不是继承,因为组合的耦合度低,代码维护性好 。不过也不这么绝对,类之间的关系适合继承就用继承。另外实现多态,也必须要用继承。类之间的关系既适合继承又适合组合,优先使用组合。
