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

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

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指针指向的内存泄露。

}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值