多态&虚函数

来源:互联网 发布:软件体系结构设计 pdf 编辑:程序博客网 时间:2024/06/08 00:31

虚函数:在类的成员函数前面加上关键字“virtual”,就称这个成员函数为虚函数。


虚函数重写:在子类中定义了一个与父类完全相同(函数名和返回类型以及参数列表都相同)的虚函数时,称子类的这个函数重写(也称覆盖)了父类的这个虚函数。


多态:一个类继承另一个类时,对一个函数进行重写,则此函数呈多态(多种形态)。


为了指明某个成员函数具有多态性,就用关键字“virtual”来标志其为虚函数。

#include<iostream>#include<string>using namespace std;class Person//父类{public:    virtual void BuyTickets()//虚函数    {        cout << "全价票" << endl;    }};class Student :public Person//子类{public:    virtual void BuyTickets()//虚函数     {        cout << "半价票" << endl;    }};void Fun(Person& p){    p.BuyTickets();}void Test(){    Person p;    Student s;    Fun(p);    Fun(s);}

上面的函数中void BuyTickets()函数就呈多态
这里写图片描述

这里写图片描述
上图的前提条件式是void BuyTickets()必须构成多态

这里我们要注意判断调用的函数是否构成多态?
1、父类的指针或者引用

class Person{public:     virtual void BuyTickets()     {        cout << "全价票" << endl;    }};class Student:public Person{public:    virtual void BuyTickets()    {        cout << "半价票" << endl;    }protected:    int _num;};//父类的指针或者引用void Fun(Person* p)//void Fun(Person& p){    p->BuyTickets();}void Test(){    Person p;    Student s;    Fun(&p);    Fun(&s);}

2、虚函数的重写(virtual+函数完全相同(协变例外))
协变是一种例外,函数返回值可以不同但有条件,条件是返回类型必须是构成父子关系的指针或引用
下面就是协变的情况

//返回值类型构成父子关系的指针或者引用//指针class Person{public:    virtual Person* BuyTickets()            {        cout << "全价票" << endl;        return this;    }};class Student :public Person{public:    virtual Student* BuyTickets()    {        cout << "半价票" << endl;        return this;    }};//引用class Person{public:    virtual Person& BuyTickets()    {        cout << "全价票" << endl;        return *this;    }};class Student :public Person{public:    virtual Student& BuyTickets()    {        cout << "半价票" << endl;        return *this;    }};

这种协变的情况也是能构成多态的

注:BuyTickets()在父类中声明为virtual,该虚函数的性质自动的继承给子类,所以Student子类中的virtual可以省略;
如果要在类外定义虚函数,只能在声明函数时加virtual,类外定义函数时不能加virtual;


注意:1、最好把基类的析构函数声明为虚函数

Why?

void func(Base* p){//...delete p;}

p是传递过来的一个对象指针,它或者指向基类对象,或者子类对象。在执行delete p时,要调用析构函数,但不知道是指向基类的析构还是子类的析构,将析构函数声明为虚函数就可以解决这个问题(基类的析构函数与子类的析构函数构成多态)。

注意:2、 构造函数不能是虚函数并且构造函数里也不能调用虚函数

因为构造时对象是不完整的,对象还是一片未定型的空间,可能会发生未定义的行为,只有在构造完成后,对象才能成为一个完整的类的实例。

注意:3、静态成员函数不能定义为虚函数,因为静态成员函数不受限于某个对象

纯虚函数

class Person{virtual void Display()=0;//纯虚函数protected:string _name;}class Student:class Person{//...}

在成员函数的形参后面写上=0,则成员函数为虚函数。包括纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。纯虚函数在派生类中重新定义以后,派生类才能实例化出对象。

其实纯虚函数就是在基类中为子类保留的一个位置,以便以后子类用自己实在的函数定义来覆盖它。如果在基类中没有保留位置,则就不能覆盖了。

原创粉丝点击