c++ primer plus阅读笔记13---虚函数 为什么要虚析构函数?

来源:互联网 发布:精品推荐软件下载 编辑:程序博客网 时间:2024/05/29 08:01

虚函数
虚函数主要是用来实现动态多态的,我们来看下边的代码:

class Base{    ...    public:        void function()        {            ...        }};class Extends:public Base{    ...    public:        void function()        {            ...        }};int main(){    Base base;    Extends extends;    Base &b1=base;    Base &b2=extends;  //父类的引用指向子类,向上转型    b1.fuctione(); //相当于:Base::function();    b2.function(); //相当于:Base::function();}

如果没有使用关键字virtual,程序将根据引用类型指针类型来选择方法,main函数中,b1,b2的引用类型都是Base,所以调用的是父类的function方法;
如果在父类的function的定义前边加上关键字virtual,则调用b2.function()相当于:Extends::function();

class Base{public://加了关键字virtual以后,这个函数成了虚函数,此时子类的function也成了虚函数,但是子类的virtual可以省略,    virtual void function()     {        std::cout<<"调用了父类的function方法"<<std::endl;    }};class Extends:public Base{public:    void function()    {        std::cout<<"调用了子类的function方法"<<std::endl;    }};int main(){    Base base;    Extends extends;    Base &b1=base;    Base &b2=extends;    b1.function();    b2.function(); //相当于:Extends::function();}

为何要使用虚函数?
加了关键字virtual以后,将会根据对象的实际类型来选择调用的函数。
我们在堆上申请一块内存存放子类的对象,并且使用父类的指针指向它,当我们是放这块内存的时候,需要调用这块内存对象的析构函数,但是我们使用的是父类的指针指向了它,如果析构函数没有不是虚析构函数,则会调用父类的析构函数,不会调用子类的析构函数。如果在子类的构造函数申请一块内存,并且在析构函数中释放这块内存,如果子类的析构函数没有被调用,将会造成内存泄露。因此需要在父类的析构函数上加上关键字virtual,这样调用析构函数的时候,会调用实际对象的类型的析构函数,如下代码:

class Base{public:    virtual void function()    {        std::cout<<"调用了父类的function方法"<<std::endl;    }     ~Base()    {        std::cout<<"调用了父类的析构函数"<<std::endl;    }};class Extends:public Base{public:    Extends()    {        std::cout<<"调用了子类的构造函数"<<std::endl;        p=new int(20); //如果父类的析构函数不是虚析构函数,则以main函数中的方式释放内存,只调用了父类的析构函数,这块内存无法释放,造成内存泄露。        for(int i=0;i<20;i++)        {            *(p+i)=i;        }    }    void function()    {        std::cout<<"调用了子类的function方法"<<std::endl;    }    void test()    {        std::cout<<"调用了子类的特有函数"<<std::endl;    }    void show()    {        for(int i=0;i<20;i++)        {            std::cout<<*(p+i)<<std::endl;        }    }    ~Extends()    {        std::cout<<"调用了子类的析构函数"<<std::endl;    }private:    int *p;};int main(){    Base *base=new Extends();    base->function();    delete base; //销毁base指向的对象,调用其析构函数,这里只会调用父类的析构函数,造成子类中的p指针指向的内存泄露。}

上边这个例子阐述了虚析构函数的重要性。

原创粉丝点击