多态性(polymorphism)
即:向不同对象发送同一个消息,不同的对象在接收时候会产生不同行为。
所谓消息,就是函数调用。
C++中多态性就是:具有不同功能的函数可以有相同的函数名称。即实现用同一个函数名调用不同的函数内容。
C++多态性分为:静态多态性 和 动态多态性
静态多态性:通过函数重载或者运算符重载实现,在编译阶段即知道函数的全部调用关系,也称为是编译时的多态性。根据表达式上下文确定该执行哪一个功能。
优点:调用速度快,效率高;缺点:缺乏灵活性。
动态多态性:在运行时实现的多态,即在运行的时候才知道操作所针对的对象。通过虚函数来实现。
?
动态多态性要解决的问题是:基类有多个派生类,且允许派生类有与基类成员相同的成员名称(包括函数名称、变量名称),在运行时候用同一个成员名称调用类对象的时候,会调用哪一个对象的成员?是基类对象的成员还是派生类对象的成员?
派生类对象可以替代基类对象向基类对象的引用初始化或赋值。
虚函数就是在基类声明函数是虚拟的,并不是实际存在的函数,在派生类中才正式定义此函数。
虚函数所解决的问题是:用基类的指针,能够在指向派生类的时候,访问派生类中与基类同名的函数。
本来,若没有声明是虚函数,那么用基类的指针,则只是指向基类对象的。若用它来指向派生类,则会发生隐式类型转换,将派生类的指针转换为基类的指针。
此时,基类指针指向的是派生类对象中基类的部分。
注意:
在基类中定义的非虚函数,在派生类中被重新定义。那么,如果是用基类的指针调用该成员函数,则系统会调用对象中基类部分的成员函数;若是用派生类的指针调用该成员函数,则系统会调用派生类对象中的成员函数。这不是多态行为,因为没有用到虚函数。
动态多态的关键点在于:
- 虚函数、同名成员函数
- 基类指针
- 指向不同派生类时候,访问的是当前派生类对象的成员函数。
函数重载 与 虚函数 区别:
函数重载处理的是同一层次上的同名函数问题。横向重载
虚函数处理的是不同层次上的同名函数问题。纵向重载
另外注意:函数重载要求 函数的参数个数 或者 函数返回类型不同。
虚函数则要求函数名、函数类型、函数参数个数及类型都与基类虚函数必须保持一致。
使用虚函数需要注意的两点地方是:
1、只能用virtual声明类的成员函数为虚函数,不能够声明类外普通函数为虚函数。其原因是:虚函数的作用是允许派生类重新定义虚函数,显然只能够在类的继承层次之中。
2、一个成员函数被声明为虚函数之后,不能够再在同一类族中再定义一个同名的非虚函数(即函数名、参数个数、类型啥的都相同)
虚函数表
特别说明:使用虚函数是有一定空间开销的。
当一个类中带有虚函数,编译系统会为该类构造一个虚函数表(virtual function table,vtable),它是一个指针数组,存放每个虚函数的入口地址。
虚析构函数
当派生类的对象从内存中清除的时候,一般是先调用派生类的析构函数,然后调用基类的析构函数。
但是,但是,但是,重要的事情说三遍。
存在这样一种情况:当用new关键词建立了临时对象,若基类中有析构函数,且定义了一个指向该基类的指针变量。在用delete 来销毁这个指针对象的时候,会发生一种情况:
系统只会执行基类的析构函数,而不执行派生类的析构函数。
因为不是虚函数,没有多态性,指针虽然赋值是派生类对象,但是只指向派生类中的基类部分。因此只是执行了基类的析构函数。
若在继承中安全地正确地执行析构函数,则最好把基类的析构函数声明为虚析构函数!!!
纯虚函数
只给出函数原型,没有函数体。在声明虚函数的时候被初始化为"=0"的函数。
声明纯虚函数的一般形式:
virtual 函数类型 函数名 (参数列表) = 0;
注意:最后有分号。纯虚函数没有函数体。=0只是个标识,告诉编译器这是个纯虚函数,没有实际意义。
纯虚函数只有函数名字不具备函数功能,不能够被调用!!!
作用是为派生类保留函数名字,以便派生类根据需要对它进行定义。如果没有保留函数名字,则不能实现多态。
凡是包含纯虚函数的类都是抽象类。抽象类不能够建立对象。
因为纯虚函数不能够被调用,所以无法实例化,即创建对象。但是,可以创建指向抽象类的指针,以此来实现多态调用。
版权声明:本文为博主原创文章,未经博主允许不得转载。