C++ 多态性有哪些

来源:互联网 发布:淘宝客服机器人 编辑:程序博客网 时间:2024/04/28 03:59
C++多态性有哪些?
     
概念:指相同的对象收到不同的消息或者不同的对象收到相同的消息时产生的不同的实现动作。
C++支持两种多态:编译时多态(静态)、运行时多态(动态)

(1)编译时多态:就是在编译期确定的一种多态。在C++中主要体现在函数模板,这里需要注意,函数重载和多态无关,很多地方把函数重载误认为是编译多态,这是错误的???
     举例说明一下函数模板是如何体现多态的:
//例1 函数模板体现编译期多态性#include <iostream>using namespace std;template <typename T>T add(T a, T b){     t c = a+b;     return c;}int main(){     int a1 = 1;     int b1 = 2;     int c1 = add(a1,b1);     cout<<"c1:"<<c1<<endl;          double a2 = 2.0;     double b2 = 4.0;     double c2 = add(a2,b2);     cout<<"c2:"<<c2<<endl;}
在例1中,我们定义了一个函数模板,用来计算两个数的和。这两个数的数据类型在使用时才知道,main函数中调用同一个函数分别计算了两个int值和两个double值的和,这就体现了多态,在编译期,编译器根据一定的最佳匹配算法来确定函数模板的参数类型到底是什么,这就体现了编译期的多态性。

(2)运行时多态性
     C++运行时多态性主要是通过虚函数来实现的。体现在具有继承关系的父类和子类之间,子类重新定义父类的成员函数成为覆盖或者重写,而虚函数允许子类重新定义父类的成员函数,即重写父类的成员函数。
     下面举例说明一下:
#include <iostream>using namespace std;class A{public:     void f1()     {          cout<<"A::f1()"<<endl;     }     virtual void f2()     {          cout<<"A::f2()"<<endl;     }};class B:public A{public:     //覆盖     void f1()     {          cout<<"B::f1()"<<endl;     }     //重写     virtual void f2()     {          cout<<"B::f2()"<<endl;     }};int main(){     A* p = new B();     B* q = new B();     p->f1();          //调用A::f1()     p->f2();          //调用B::f2(),体现多态性     q->f1();          //调用B::f1()     q->f2();          //调用B::f2()     return 0;}
 说说例2中关于体现多态性的问题,我们在父类即A类中定义了一个虚函数f2()——由关键字virtual修饰。既然是虚函数,允许子类重写这个函数,于是我们在子类即B类中重写了函数f2()。之后我们在main函数中定义了一个A类指针p,请注意,虽然定义的是一个父类指针,但是它指向的却是一个子类的对象(new B()),然后我们用这个父类的指针调用f2(),从结果来看,实际上调用的是子类的f2(),并不是父类的f2(),这就体现了多态性。虽然p是父类指针,但是它指向的是子类对象,而且调用的又是虚函数,那么在运行期,就会找到动态绑定到父类指针上的子类对象,然后查找子类的虚函数表,找到函数f2()的入口地址,从而调用子类的f2()函数,这就是运行期多态。
     接下来我们再来看看p->f1();这句话,从运行结果来看,调用的是父类的f1()函数,这里是为什么没有体现多态呢?原因很简单,因为f1()不是虚函数,所以根本就没有多态性,虽然子类和父类都有f1()函数,但是子类仅仅是覆盖或者说是隐藏了父类的f1()函数,注意这里不是重写,是覆盖。而p是父类指针,所以只能调用父类的f1()函数。而指针q的类型为子类指针,所以q->f1();调用子类的函数f1(),q->f2();调用子类的函数f2();

(3)C++纯虚函数 
定义:纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法,基类中实现纯虚函数的方法是在函数原型后面加“=0”。例如:
virtual void f() = 0;

为什么要引入纯虚函数:
1、为了使用多态特性,我们必须在基类中定义虚拟函数。 
2、在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。 为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要求在派生类中必须予以重写以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。纯虚函数永远不会被调用,它们主要用来统一管理子类对象。



原创粉丝点击