** OOP基于三个基本概念:数据抽象(类)、继承(派生)、动态绑定(虚函数);其中,动态绑定使编译器能够在运行时决定是使用基类中定义的函数还是派生类中定义的函数。
15.1 OOOP:概述
** OOP的关键思想是:多态性。
** C++中,多态性仅用于通过继承而相关联的类型的引用或指针。
** 派生类能够继承基类定义的成员,可以重定义那些与派生类类型相关的成员函数。
** C++中,基类必须指出希望派生类重定义哪些函数(virtual),希望派生类继承的函数不能定义为虚函数。
** void fun(base_class &obj) {obj.fun1();}
虽然参数为base_class的引用,但是可以将base_class对象或其派生类对象传给它;调用哪个版本的fun1()将依赖于传给fun的实参类型。
** C++中,通过基类的引用(或指针)调用虚函数时,发生动态绑定;用引用(指针)调用的虚函数在运行时确定,被调用的函数由引用(指针)所指对象的实际类型决定。
15.2 定义基类和派生类
** 继承层次的根类一般都要定义虚析构函数。
** virtual的目的是启用动态绑定;除了构造函数,任意非static成员函数都可以为虚函数;virtual只能在成员函数声明中出现,不能再类外部的函数定义中出现。
** 基类通常应将需要派生类重定义的函数定义为虚函数。
** private成员只能由类成员和友元访问;派生类不能访问基类的private成员,但可以访问基类的protected成员(只能通过派生类对象访问其基类的protected成员,不能访问其基类类对象的protected成员,如:child_class类有成员函数ch_fun(base_class &obj),base_class有protected成员base_pro,则ch_fun可以访问自己的protected成员(直接集成自base_class),不能访问obj的base_pro)。
** 关于访问控制与继承:提供给派生类的接口是protected与public成员。
** 可以继承多个基类。
** 派生类定义:
class child_class_name : public/ protected/ private base_class
{};
** 派生类一般会重定义所继承的虚函数。若没有重定义,则使用基类的版本;若要重定义,需对该虚函数进行声明,且声明方式与基类完全匹配(例外:返回对基类的引用/ 指针的虚函数,此时派生类返回类型可为2种),此时是否保留virtual关键字均可。
** 派生类对象的组成:派生类自身的非static成员,以及基类的非static成员(public与protected成员)。
** 用作基类的类必须是已经定义的(类的声明:class class_name;),这说明:不能从类自身派生出类。
** 派生类的声明不包含派生列表。
** 发生动态绑定的条件:1、虚函数;2、必须通过基类的引用/ 指针进行函数调用。
** 因为每个派生类对象都包含基类部分,因此可以用指向基类的指针指向派生类对象,也可以将基类的引用绑定到派生类对象的基类部分;所以使用基类的引用/ 指针时,不知道引用/ 指针对应对象的类型。
** 任何在基类对象上的操作也可以通过派生类对象使用,因此将派生类对象当做基类对象是安全的。
** 只有基类的引用/ 指针才有可能是多态的,对象是非多态的。
** 覆盖虚函数机制:当希望强制函数调用虚函数的特定版本时,可以使用作用域操作符:class_name::fun()。
** 派生类虚函数调用基类版本时,必须显式使用作用域操作符,否则将导致自身调用,从而导致无穷递归。
** 虚函数也可有默认实参;若一个调用省略了具有默认值的实参,则所用的值由调用该函数的类型定义。
** 不要再统一虚函数的基类版本和派生类版本中使用不同的默认实参(??)。
** 对基类成员的访问权限由“基类的成员访问级别和派生类派生列表的访问标号”共同控制;派生类只能进一步限制而不能放松对所继承成员的访问。
** 派生类派生列表的访问级别:
public:基类的public成员作为派生类的public成员,基类的protected成员作为派生类的protected成员;
protected:基类的public和protected成员作为派生类的protected成员;
private:基类的所有成员在派生类中均为priva成员。
** 使用private和protected派生的类不继承基类的接口,这些派生通常被成为实现继承(?是不是只有虚函数重定义?)。
** 继承层次的设计:“是一种”用public;“有一个”。
** 派生类可以恢复继承成员的访问级别,但是不能使访问级别比基类中指定的更严格或更宽松。
** 访问级别的恢复:base_class有public成员item,child_class按private继承base_class,则child_class中,item为private(?这时,item是child_class的私有成员,还是child_class根本不能访问item?按我的理解,这时item根本不能访问item,那么不能访问base_class的所有成员了,只能进行虚函数重定义以及添加自己的成员?),若要恢复,在child_class定义中进行定义:
public:
using base_class::item;
** 使用class定义的派生类默认为private继承,而struct定义的派生类默认为public继承。
** 友元可以访问private和protected成员;友元关系不能继承(基类的友元对基类的派生类没有特殊访问权限);友元的指定:在类定义里面的开头(没有访问控制标识符):friend class class_name;
** static成员遵循常规的访问控制;如果基类定义了static成员,则整个继承层次中只有一个这样的成员;每个static成员只有一个实例(我的理解应该是对的:除了基类中的定义,不能在派生类中再定义它;可以按照child_class::m_static形式调用同一个版本的static成员)。
** 妹的,这一节看了近4个小时,基础不扎实。。。
15.3 转换与继承
** 因为派生类对象也是基类对象,派生类转换到基类的原则是:
派生类(对象地址/指针)——> 基类(指针);
派生类(引用,对象)——> 基类(引用);
将派生类对象传给接受基类对象的函数时,该派生类对象额基类部分被复制给形参。
使用派生类对象对基类对象进行初始化或赋值(初始化或赋值实际上是在调用函数:分别调用了构造函数和赋值操作符),但没有从派生类对象到基类对象的直接转换。(?后半句到底是什么意思,难道有错?);
** 基类到派生类转换的原则:不能自动转换。
** 用派生类对象对基类对象进行初始化或赋值时有2种可能性:
1)基类显式定义了将派生类对象复制或赋值给基类对象的构造函数或赋值操作符;
2)基类一般定义自己的复制构造函数和赋值操作符,它们接收一个基类引用(const)的形参,考虑到存在从派生类引用到基类引用的转换,so....
15.4 构造函数和复制控制
** 构造函数和复制控制成员不能继承。
** 派生类的构造函数(不论是否是默认)除了初始化派生类的数据成员外,还初始化其基类部分(调用基类的默认构造函数)。
** 合成默认构造函数(如果一个没有任何constructor的class 派生自一个"带有default constructor"的base class.那么它的default constructor会被合成出来。)
** 向基类构造函数传递实参:派生类构造函数通过将基类包含在构造函数初始化列表中来间接初始化基类成员:
child_class(const int& base_item, const int&ch_item):
base_class(base_item), child_item(ch_item) {}
** 只能初始化直接基类(派生列表中指定的类)。
*暂停,够用就行*