第四章
多态
静态多态性:编译阶段绑定(早期联编),通过函数重载实现
动态多态性:运行时动态绑定(之后联编),通过虚函数和继承实现
动态绑定的条件:
- 在虚基类中定义虚函数
- 使用指向基类的指针或引用调用虚函数
虚函数必须是成员函数,且必须是非静态成员函数。(静态成员函数都是早期联编的)。
当基类中某个成员函数定义为虚函数时,在派生类中就要重新定义该函数,且函数签名必须完全一致。
虚函数不能是内联函数
构造函数不能是虚函数
析构函数可以是虚函数
虚函数的覆盖
出原型完全相同的虚函数在基类、派生类中形成覆盖关系外,其他同名函数形成隐藏关系。隐藏和覆盖都让派生类对象无法访问基类同名函数。但当通过基类指针或引用访问派生类中的隐藏或覆盖函数时会有不同结果。覆盖函数会调用派生类中的新定义的函数,隐藏函数会调用基类中的函数而不能调用派生类中的新定义的函数。
虚函数的传递性
虚函数具有传递性,即在多重继承中基类派生的所有派生类的原型相同的函数都是虚函数,具有虚函数的一切特性。通过基类的指针或引用可以调用该基类派生的所有派生类的所有原型相同的函数,且都具有多态性。
在有继承关系时,析构函数应设计为虚函数。
构造函数尽量采用初始化列表的方式初始化派生类的构造函数,以提高效率。因为初始化列表会在函数体内的赋值语句执行前执行,且效率比函数体内的赋值语句高。
抽象类
Class 类名
{
Public:
Virtual 函数返回类型 函数名(参数表)=0;
}
虚函数必须有函数实现,纯虚函数一般在基类中没有实现。
纯虚函数首先必须是成员函数。
纯虚函数是虚函数的一种特例,具有虚函数的性质——通过它可以实现动态多态性。
如果在派生类中没有对基类的纯虚函数进行定义,那么他在派生类中依然是纯虚函数,派生类则依然是抽象类。
一个类如果含有纯虚函数,那么该类只能作为基类用于派生新类,不可以实例化。(类似与java中的接口)
抽象类主要表达一个类族的共同特征或者行为,以方便该类族的派生类继承和实现,从而更好的实现多态性。
不能直接用抽象类对象作为函数参数类型、函数返回值类型或显示转换类型。
函数参数设置为抽象基类的指针或引用时,使用抽象基类的指针或引用(指向子类)传进去可动态绑定。
函数重载
函数名相同,但是参数表不同。
运算符重载
<函数返回值类型> operator <运算符> (<形参表>)
{
<函数体>
}
成员运算符重载,参数个数必须必运算符原来的参数个数少1,表示默认隐含的另一个参数是该类的对象,该类的对象被隐含作为第一操作数。
非成员运算符重载,参数个数与运算符原来的个数相同。<<和>>运算符只能重载为非成员运算符。
单目运算符最好重载为成员运算符,双目运算符最好重载为非成员运算符。
重载前缀++或—
<函数类型> operator ++();
重载后缀++
<函数类型> operator ++(int); int仅作为与前缀的区别
赋值运算符重载类似于拷贝构造函数
通常凡事包含动态分配成员或包含指针成员的类,都需要提供拷贝构造函数;提供拷贝构造函数的同时,还应该考虑重载赋值运算符。
调用拷贝构造函数的情况:
1当以对象作为函数参数,以值传递的方式传入函数体时;2当以对象作为函数返回值,以值传递的方式从函数返回对象时;3当用对象初始化另一个对象时。