析构函数为虚函数

/*
基类析构函数[是虚函数]:
    指向派生类的基类指针在析构的时候
    [普通指针,shared_ptr,unique_ptr][都会先调用派生类的析构函数,然后再调用基类的析构函数]
 */
/*
基类析构函数[不是虚函数]:
    指向派生类的基类指针在析构的时候
    [普通指针,unique_ptr][只会调用基类的析构函数,不会调用派生类的析构函数]
    [shared_ptr][会先调用派生类的析构函数,然后再调用基类的析构函数]
 */
#include <iostream>
#include <string>
#include <memory>

class BaseA
{
    int data;
    std::string msg;
public:
    BaseA() {
        msg="BaseA message";
    }

    /*
    ~BaseA() {
        std::cout<<__FUNCTION__<<std::endl;
    }
     */
    
    virtual ~BaseA() {
        std::cout<<__FUNCTION__<<std::endl;
    }

    virtual void show_msg() {
        std::cout<<msg<<std::endl;
    }
};

class DeriveA:public BaseA
{
    int data;
    std::string msg;
public:
    DeriveA() {
        msg="DeriveA message";
    }

    ~DeriveA() {
        std::cout<<__FUNCTION__<<std::endl;
    }

    
    void show_msg() {
        std::cout<<msg<<std::endl;
    }
};

void UsePrivateFunc() {
    {
        std::cout<<"ptr BaseA:"<<std::endl;
        BaseA* ptr_BaseA(new DeriveA());
        ptr_BaseA->show_msg();
        delete ptr_BaseA;
    }
    std::cout<<"\n";
    
    {
        std::cout<<"unique_ptr BaseA:"<<std::endl;
        std::unique_ptr<BaseA> uptr_BaseA(new DeriveA());
        uptr_BaseA->show_msg();
    }
    std::cout<<"\n";
    
    {
        std::cout<<"shared_ptr BaseA:"<<std::endl;
        std::shared_ptr<BaseA> sptr_BaseA(new DeriveA());
        sptr_BaseA->show_msg();
    }
}

int main(int argc,char* argv[])
{
    UsePrivateFunc();
    return 0;
}

析构函数是虚函数的输出结果:

1430944-20190613205843960-1856916566.png

析构函数不是虚函数的输出结果:

1430944-20190613205915123-429516597.png

转载于:https://www.cnblogs.com/smallredness/p/11019451.html

<think>好的,用户想了解C++中虚析构函数的作用和必要性。我之前学过一些相关知识,但得仔细回忆一下。根据提供的引用内容,首需要理解析构函数在继承体系中的调用机制。 记得引用3提到,如果基类析构函数不是虚函数,当用基类指针指向派生类对象并删除该指针时,只会调用基类析构函数,而派生类析构函数不会被调用。这会导致派生类中分配的资源无法释放,造成内存泄漏。比如,用户可能有一个基类Base和一个派生类Derived,Derived的析构函数负责释放某些内存,如果析构函数不是虚的,那么删除基类指针时,Derived的析构函数不会被调用,导致内存泄漏。 引用2中也强调了这一点,说明如果基类析构函数不是虚的,派生类析构函数不会执行,导致资源泄漏。这种情况下,将基类析构函数声明为虚函数可以确保在删除基类指针时,正确调用派生类析构函数,进而调用基类析构函数。引用4提到,派生类析构函数执行完后会自动调用基类析构函数,这个过程是隐式的。 但是,不是所有情况都需要虚析构函数。引用2指出,只有当类作为基类时,才需要将析构函数设为虚函数。因为虚函数会增加类的存储空间,每个对象需要维护一个虚函数表指针,这可能影响性能。所以,如果类不会被继承,或者不需要多态删除,就不必使用虚析构函数。 总结来说,虚析构函数的作用是确保通过基类指针删除派生类对象时,能够正确调用派生类基类析构函数,防止资源泄漏。必要性在于处理多态场景下的对象销毁,避免内存泄漏。而使用时需权衡,仅在基类中需要时才声明虚析构函数,避免不必要的开销。 接下来需要组织这些点,用用户提供的引用作为支持,并生成相关问题。</think>### C++虚析构函数的作用与必要性 #### 作用说明 1. **确保派生类资源释放** 当通过**基类指针删除派生类对象**时,若基类析构函数未声明为虚函数,编译器会仅调用基类析构函数,导致派生类资源泄漏[^2][^3]。例如: ```cpp Base* obj = new Derived(); delete obj; // 若基类构非虚,仅调用Base::~Base() ``` 若将基类析构函数声明为虚函数(`virtual ~Base()`),则会触发动态绑定,正确调用派生类析构函数,再隐式调用基类析构函数[^1][^4]。 2. **支持多态对象销毁** 虚析构函数是**多态特性在对象销毁阶段的体现**,确保通过基类接口操作派生类对象时,销毁过程能完整覆盖所有层级[^3]。 #### 必要性分 1. **基类设计的关键约束** 若类需要作为基类且可能通过基类指针删除派生类对象,则必须声明虚析构函数。否则会导致: - 派生类析构函数调用 → 资源泄漏 - 基类析构函数调用基类资源泄漏(但引用4指出,派生类析构函数会隐式调用基类析构函数,此处可能存在矛盾,需进一步确认) 2. **性能与存储权衡** 虚析构函数会引入虚函数表(vtable),增加对象存储开销(通常每个对象多一个指针大小)。因此: - 仅当类需要作为基类时声明虚析构函数 - 非基类或不会被多态使用的类无需虚析构函数 #### 代码示例 ```cpp // 正确实现 class Base { public: virtual ~Base() {} // 虚析构函数 }; class Derived : public Base { public: ~Derived() override { // 释放派生类资源 } }; // 使用场景 Base* obj = new Derived(); delete obj; // 调用Derived::~Derived() → Base::~Base() ``` #### 典型错误案例 ```cpp class Base { public: ~Base() {} // 非虚析构函数 }; class Derived : public Base { public: int* allocated_memory; Derived() { allocated_memory = new int[100]; } ~Derived() { delete[] allocated_memory; } // 不会被调用! }; Base* obj = new Derived(); delete obj; // 仅调用Base::~Base() → 内存泄漏 ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值