目录
●多态的实现类型
多态性概述:
● 面向对象的继承性特征较客观的反应了类与类之间的层次关系,多态性则是讨论这种不同层次的类以及一个类的内部,类的同名成员函数之间的关系问题,是解决功能和行为的再抽象问题。
● 多态性是指类中同一函数名对应多个具有相似功能的不同函数,可以使用相同的调用方式来调用这些具有不同功能的同名函数的特性。
多态性的分类:
●重载多态
●强制多态
●参数多态
●包含多态
若从实现的角度划分多态:
●编译时多态。编译时多态是指在编译阶段由编译系统根据程序的操作数据确定具体调用哪一个同名函数。
●运行时多态。运行时多态是指在程序运行过程中根据产生的信息动态地确定需要调用哪一个同名函数。
●多态性实现的相关技术
联编
● C++采用联编(binding)技术来支持多态性
●多态性的实现过程中,确定调用哪一个同名函数的过程就是联编,又称为绑定(有些文献称为编联或束定等)
●联编是指计算机程序自身彼此关联的过程,也就是将一个标识符(函数名)和一个存储地址联系在一起的过程。
●按照联编进行的阶段的不同可以分为: 静态联编 和 动态联编
1.静态联编
●静态联编是指在编译阶段完成的联编方式,又称为“早期联编”或“前联编”
●静态联编的特点:函数调用速度快、效率高、不足之处是变成不够灵活
2.动态联编
●动态联编是指有一些联编工作无法在编译阶段准确完成,只有在程序运行时才能确定将要调用哪一个函数,这种在程序运行过程中进行的联编方式称为动态联编,又称为“晚期联编”或“后联编”
●动态联编的特点:使编程更具灵活性、对问题的抽象更方便、程序的易维护性更好、与静态联编相比调用速度较慢。
●动态联编的实现方式:继承和虚函数
●虚函数的定义和使用
●虚函数是动态联编的主要实现方式,是动态联编的基础。
●虚函数是非静态的成员函数,经过派生之后,虚函数在类族中可以实现运行时多态。
1.虚函数的声明
虚函数是一个在基类中通过virtual声明,并在一个或多个派生类中被重新定义的成员函数。声明虚函数的格式如下:
2.虚函数的说明
●虚函数实际上是一个在类的声明中使用关键字virtual来限定的成员函数。
● 成员函数一旦被声明为虚函数,则无论该类被继承了多少层,在各层次的派生类中,该函数都保持虚函数的特性。当类的某成员函数被声明为虚函数后,派生类的相应成员函数就具有多态性。
●在派生类中重新定义虚函数时,可以省略关键字virtual,但必须保证函数的返回值类型、参数类型与基类中该虚函数的声明完全一致。
●如果在派生类中没有重新定义虚函数,则该派生类的对象将使用基类的虚函数代码。
●通常可将类族中的具有共性的成员函数声明为虚函数,不具备多态性特征的函数不能声明为虚函数。
不具备多态特性的函数
●静态成员函数不能声明为虚函数。静态函数不属于某一个对象,不具备多态性的条件和特征。
●内联成员函数不能声明为虚函数。因为内联函数的执行代码是确定的,不具有多态性的特征。
●构造函数不能是虚函数。
3.虚函数的调用
实现动态联编方式的前提:
●先要声明虚函数
●类之间满足赋值兼容规则
●通过对象指针与对象引用来调用虚函数。
4.虚函数的作用
应用虚函数,可以使程序员不必过多的考虑类的层次关系,无须显示的写出虚函数的路径,只需将对象指针指向相应的派生类或引用相应的对象,就可以实现动态联编,实现对消息的正确响应。
5.虚析构函数
虽然C++中不能声明虚构造函数,但可以声明虚析构函数,而且常被定义为虚函数。
虚析构函数的定义:
●纯虚函数与抽象类
1. 纯虚函数的定义
纯虚函数在声明时要在函数原型的后面赋0。
纯虚函数声明的一般格式如下:
2.抽象类的使用
●抽象类是带有纯虚函数的类,通过抽象类为一类族提供一个公共的接口——纯虚函数
●抽象类只能用作其他类的基类,不能建立抽象类对象
●建立抽象类是为了通过它多态的使用其成员函数
●抽象类的构造函数与析构函数不应调用纯虚函数
●函数重载和运算符重载
函数重载是指两个或两个以上的函数具有相同的函数名,但参数类型不一致、参数个数不同或返回值类型不同,从而使重载的函数虽然函数名相同,但功能上却不完全相同。
1.函数重载的分类
函数重载包括:
●成员函数重载 如:构造函数重载 、一般成员函数重载
●普通函数重载 如:求立方体函数重载
2.运算符重载
●C++预定义的运算符只能对基本类型的数据进行操作,不能用于自定义数据类型的运算。
●对于用户自定义的数据类型往往需要有类似的运算操作,客观上需要定义适用用户自定义数据类型的有关运算,这就是运算符重载问题
(1)运算符重载规则
①C++的预定义的运算符除了以下少数几个之外,其他均可以重载。 不能重载的运算符只有5个,分别是:
成员访问运算符: .
成员指针运算符:.*
作用域运算符:∷
运 算 符:sizeof
三目运算符:?:
②只能重载C++预定义中已有的运算符,不可自己“创造”新的运算符进行重载。
因为基本数据类型之间的关系是确定的,如果允许定义新运算符,那么,基本数据类型的内在关系将会发生混乱。
③重载之后的运算符的优先级和结合性都不会改变,同时保持原有预定义运算符的语法结构不变,而参数和返回值类型是运算符重载的实质所在。
④运算符重载是针对新的数据类型的实际需要,对原有运算符进行的适当改造与扩充。
一般情况下应保持重载的功能与预定义运算符原有功能类似,不能改变运算符操作数个数,同时要求至少有一个操作数是用户自定义数据类型。
⑤运算符重载有两种方式:
●重载为类的成员函数 除后缀运算符“++”和“--”,其参数的个数比原来的操作数个数要少一个
●重载为类的友元函数 单目运算符一般重载为成员函数
⑥“++”和“--”单目运算符重载为类的成员函数时,由于不能区分是运算符前置还是后置,C++约定,若重载函数参数表有一个整型参数,表示运算符后置
(2) 运算符重载为成员函数
●运算符重载为成员函数后,可以自由访问本类的任何成员。
●对于双目运算符,其左操作数一定是对象本身,由this指针给出,另一个操作数则需要通过运算符重载函数的参数表进行传递。
●对于单目运算符,对象的this指针直接给出操作数,因此不再需要任何其他参数。
(3)运算符重载为成员函数
operator是定义运算符重载函数的关键字,形参表中最多有一个形参。
(4)运算符重载为友元函数
●运算符也可以重载为类的友元函数。
●当运算符重载为友元函数时同样可以自由地访问类的所有成员。
●运算符重载为友元函数时,运算符所需要的操作数都需要通过函数的形参来传递,在参数表中参数从左至右的顺序就是运算符操作数的顺序。
运算符重载为友元函数的格式
其中,形参表中最多只能有两个形参。