您的位置:首页 > 其它

继承与多态

2016-01-23 22:03 183 查看
1、派生与继承

在C++中,继承分为单继承和多继承:
单继承:派生类只有一个直接基类的继承方式;
多继承:派生类有多个直接基类的继承方式;

派生类定义格式:
class <派生类名> : <继承方式><基类名>
继承方式有三种:
public 公有继承:基类中的每个成员在派生类中保持同样的访问权限;
private 私有继承:基类中的每个成员在派生类中都是private成员,且不能再被派生类的子类所访问;
protected 保护继承:基类中的public 和 protected 成员在派生类中都是protected 成员,private成员在派生类中仍为private成员;

在C++中,若未指定继承方式,则缺省的继承方式为私有继承;
不管是什么继承方式,派生类的成员函数和友元函数都可以访问基类中的公有成员和保护成员,但不能访问私有成员。在公有继承时,派生类的对象只能访问公有成员,在保护继承和私有继承时,派生类对象不能访问基类中的任何成员。
如果我们指定一个派生类私有继承自基类,那么我们怎样让派生类对象能够调用基类中的成员函数呢,解决办法是我们可以派生类中使用访问申明语句,将成员函数的访问权限恢复为public。该访问申明是私有继承方式中的一种调用机制,用于在私有继承方式下恢复指定成员的访问权限。

2、派生类的构造、析构函数

派生类对象的数据结构由基类中说明的数据结构和派生类中说明的数据结构共同构成,在创建派生类对象时,派生类对象的初始化,不仅要给派生类中的数据成员初始化,还要给基类中的数据成员初始化,如果派生类中还有子对象时,还要对子对象进行初始化。
构造函数的调用顺序如下:
a.基类构造函数
b.子类构造函数
c.派生类构造函数
执行派生类的析构函数时,也要调用基类及子对象的析构函数,析构顺序如下:
a.派生类析构函数
b.子对象析构函数
c.基类析构函数

3、类成员重定义

重定义:子类需要修改或扩展基类某个成员的功能时利用的机制;
特征:
a.可以对基类的数据成员重定义,亦可对基类的成员函数重定义
b.重定义新成员既可与基类完全相同,亦可与基类成员函数名相同而参数不同
注:
a.不管子类重载的成员函数的参与与基类是否完全相同,都会构成重载;
b.重定义是指在不同的作用域中定义的成员函数名相同,参数相同或不同的情况;
c.重定义的成员会覆盖其父类成员

4、多继承

定义:若派生类有两个或两个以上的直接基类,我们称之为多继承。
格式:class <派生类名> : <继承方式1><基类名1>,<继承方式2><基类名2>......
多继承派生类的构造函数执行顺序:先执行所有基类的构造函数,再执行派生类本身的构造函数

多继承中的二义性问题:
一般情况下,派生类对象的访问是唯一的,但在多继承情况下,可能出现派生类对其类成员访问的不唯一性,即二义性。出现二义性的两种情况:
a.调用不同类的具有相同名字的成员时可能出现二义性;
b.访问共同基类的成员时可能出现二义性;
针对二义性的解决方法:
a.用类名对成员加以限定;
b.使用虚基类,使得在继承间接共同基类时只保留一份成员;(参考菱形继承)

5、多态性

定义:指不同类对象发出相同的消息将会有不同的行为,消息指对类的成员函数的调用,不同的行为是指不同的实现;

函数重载:允许在相同作用域内,相同的函数名对应着不同的实现;
条件:参数的类型或个数不同
成员函数的重载有以下三种表达方式:
a.在一个类中重载
b.在不同类中重载
c.基类的成员函数在派生类中重载
同名的重载函数在编译时区分,有三种区分方式:
a.根据参数的不同加以区别
b.使用类作用域符“: :”区分
c.根据类对象区分

子类型:
在继承关系中,若类B是类A以公有继承形式产生的派生类,则类B包含了类A的行为,且其本身还可具有新的行为,称类B是类A 的一个子类型。
若类B是类A的子类型,则类A 的对象可以操作的函数,类B的对象也可以进行操作,称为类B适应类A,子类型的作用就在于类型适应,即在公有继承方式下,派生类的对象,指向派生类对象的指针和对象的引用都适应于基类的对象,指向对象的指针和对象的引用所能使用的场合。

6、静态联编与动态联编

静态联编:在程序编译链接阶段进行联编,也称早期联编。静态联编在程序运行之前完成,所调用的函数与执行该函数的代码之间的关系已确定;
动态联编:在程序运行时进行联编,也称晚期联编。动态联编在运行时确定程序中的函数调用与执行该函数代码之间的关系;
注:继承是动态联编的基础,虚函数是动态联编的关键

7、虚函数

格式:virtual <类型说明符><函数名>(<参数表>)
特征:
a.若一个类中的成员函数说明为虚函数,那么该成员函数可能在派生类中存在不同的实现版本;
b.由于存在虚函数,编译器进行动态联编,此时调用虚函数的对象在运行时确定,实现动态联编的多态性

基类函数具有虚特性的条件:
a.在基类中,将该函数说明为虚函数;
b.定义基类的公有派生类;
c.在基类的公有派生类中重载该虚函数;
d.定义指向基类的指针变量,它指向基类的公有派生类对象;
注:重载虚函数与一般重载函数不同,其要求函数名、返回类型、参数个数、参数类型和顺序完全相同

8、重载、重定义、重写比较

重载:作用域相同,函数名相同,参数不同。属于同一种函数的不同实现;
重定义:作用域不同,函数名相同,参数相同/不同。子类覆盖基类的同名函数,函数类型可不同;
重写:作用域不同,函数名相同,参数相同。子类覆盖基类的同名函数,函数类型相同;

9、纯虚函数与抽象类

定义:没有具体实现的虚函数。
格式:virtual <函数类型> <函数名>(<参数表 >) = 0;
作用:多数情况下,基类中不能对虚函数给出有意义的实现,需要将其声明为纯虚函数,其实现留给该基类的派生类完成。
特征:
a.纯虚函数相当于接口模板,不能直接实例化,需要派生类实现函数定义;
b.一个类中如果定义了纯虚函数,那么这个类就成了抽象类,C++规定抽象类不能定义对象;

10、虚析构函数

构造函数不能说明为虚函数,而析构函数能说明虚函数。如果一个基类的析构函数被说明为虚函数,那么其派生类中的析构函数也是虚析构函数。
注:虚析构函数一般用在基类,用于防止对衍生类对象delete基类指针造成的内存泄露。
基类的析构函数为虚函数,且衍生类有自定义析构函数实现时,delete基类指针时会同时调用衍生类的析构函数。若基类的析构函数不是虚函数,那么在调用基类的析构函数时,基类的析构函数将不能释放衍生类的资源。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: