|
多态性(Polymorphism)同继承性一样,是面向对象程序设计的标志性特征,是一个考查重点。
|
|
|
多态性是考虑在不同层次的类中以及在同一类中,同名的成员函数之间的关系问题。函数的重载和运算符的重载都属于多态性中的编译时的多态性。运行时的多态性是以虚基类为基础的多态性。
|
|
|
|
多态是指同样的消息被不同类型的对象接受时导致不同的行为(不同的实现或调用了不同的函数)。所谓消息,是由"类::方法"(功能)和"方法的实参"(消息数据)共同组成的。
|
|
|
产生多态性的原因是:不同的对象在处理同样的消息时,使用的方法实现(成员函数的函数体)不同。"多态性"是与"类的派生和继承"联系在一起的,是基类中所定义方法的"多态性"。对于在派生类中新增加的方法,是没有多态性的。
|
|
|
|
|
(2)强制多态:强制类型转换。把一个变量的类型变换成另一种类型,以符合一个函数或者操作的要求。例如,加法运算符在执行浮点数和整数的相加时,首先把整数转换成浮点数,然后再相加。
|
|
|
(3)包含多态:主要通过虚函数来实现。强调不同类中的同名成员函数的多态行为。
|
|
|
|
|
(1)编译时的多态性:通过函数的重载和运算符的重载来实现。
|
|
|
(2)运行时的多态性:是指在程序执行前,无法根据函数名和参数来确定该调用哪一个函数,必须在程序执行过程中,根据执行的具体情况来动态地确定。这种多态性是通过类继承关系和虚函数(Virtual Function)来实现的。
|
|
|
|
虚函数是前面有virtual关键字的类的成员函数,定义虚函数的格式如下:
|
|
|
|
注意:virtual关键字只用在类定义里的函数声明中,写函数体时不用。
|
|
|
另外,如果基类中的函数不是虚函数,即没有virtual关键字,即使派生类中写了virtual也没有用,不能实现多态。
|
|
|
|
(1)派生类中定义虚函数除必须与基类中的虚函数同名外,还必须同参数表、同返回类型。如基类中返回基类指针,派生类中返回派生类指针是允许的。
|
|
|
|
|
(4)实现动态多态性时,必须使用基类指针或引用,使该指针指向不同派生类的对象,并指向虚函数。
|
|
|
|
(6)析构函数可定义为虚函数,构造函数不能为虚函数。在基类中及其派生类中都有动态分配的内存空间时,必须把析构函数定义为虚函数,实现撤销对象时的多态性。
|
|
|
|
(1)纯虚函数(Pure Virtual Function):指被标明为不具体实现的虚拟成员函数。定义纯虚函数的一般格式为:
|
|
|
|
|
|
|
|
."=0"本质上是将指向函数体的指针定义为NULL。
|
|
|
.在派生类中必须有重新定义的纯虚函数的函数体,这样的派生类才能用来定义对象。
|
|
|
|
抽象类只能作为基类来派生新类使用,不能创建抽象类的对象,可声明一个抽象类的指针和引用。
|
|
|
在抽象类的成员函数内可以调用纯虚函数,但是在构造函数或析构函数内部不能调用纯虚函数。因为在构造函数或析构函数内部调用虚函数采用的是静态联编,即编译时就要生成调用该函数的指令,而纯虚函数是没有代码的,所以这样的调用指令无法生成,因此编译会报错。在普通成员函数内可以调用纯虚函数,尽管纯虚函数是没有代码的,但是此时是动态联编,编译时不需要生成调用该函数的指令,所以编译可以通过。在运行时决定到底调用的是自己还是派生类的函数,因为自己是个抽象类,不可能生成对象,所以不可能调用自己的这个纯虚函数。
|
|
|
|
只要基类的析构函数是虚函数,那么派生类的析构函数不论是否使用virtual关键字,不论是自己定义的还是编译器默认生成的,都自动成为虚函数。
|
|
|
一个类的构造函数会在执行自己代码之前,依派生顺序自动调用它的所有直接基类的构造函数;一个类的析构函数也会在执行完自己的代码之后,以与构造函数调用次序相反的顺序自动调用其所有直接基类的析构函数。一般来说,一个类如果定义了虚函数,则应该将析构函数也定义成虚函数。
|
|
|