关于delete父类指针,删除堆区数据的问题

问题是

如果在堆区创建一个子类对象,用父类指针接收它(子类中除继承父类中属性,不做属性添加),再delete父类指针,这时堆区中的子类对象会不会删除干尽(就是是否会造成数据泄露)?是否还存在这个子类对象?如果存在占1字节还是不占字节?

从理论上不会造成数据泄露,但肯定会有其他问题得有个具体的例子测试下,如果使用父类指针删除子类对象只调用父类的析构函数,子类对象这个时候还是再得,字节一般不变,跟子类大小一样,你可以在父类中添加一个虚析构函数,让子类的析构函数能用就行

跑这个代码,看类的构造和析构打印输出,就能理解了

#include <iostream>
 
using namespace std;

class A{
public:
    A(){ cout<<"A()"<<endl; }
    ~A(){ cout<<"~A()"<<endl; } 
};

class B{
public:
    B(){ cout<<"B()"<<endl; }
    virtual ~B(){ cout<<"~B()"<<endl; } 
};

class C:public A{
public:    
    C(){ cout<<"C()"<<endl; }
    ~C(){ cout<<"~C()"<<endl; }   
};

class D:public B{
public:    
    D(){ cout<<"D()"<<endl; }
    ~D(){ cout<<"~D()"<<endl; }   
};

int main() {
    A* a = new C();
    B* b = new D();
    cout<<"delete A"<<endl;
    delete a;
    cout<<"delete B"<<endl;
    delete b;
    return 0;
}

子类对象中除了继承父类中的属性外,还有自己添加的属性,这些属性需要在释放内存时一并释放。
如果不释放这些额外的属性,就会导致数据泄露。因此,在使用完子类对象后,一定要使用delete操作符来释放内存。

  • 你可以看下这个问题的回答https://ask.csdn.net/questions/178035
  • 这篇博客也不错, 你可以看下用new运算符为一个包含20个整数的数组分配内存,输入若干个值到数组中,分别统计其中正数和负数的个数,输出结果,再用delete运算符释放动态内存空间。
  • 以下回答由chatgpt基于相关博客总结生成:

    答案:

    如果在堆区创建一个子类对象,并使用父类指针接收它,那么delete掉父类指针时,虽然子类对象仍然存在,但是它的析构函数不会被调用,会造成内存泄漏。这是因为基类指针只能访问到基类成员,而不能访问派生类新增的成员,所以delete指针所指的内存时,只会调用基类的析构函数,而不会调用派生类的析构函数。因此,为了避免这种情况的发生,应该在父类中将析构函数设置为虚函数,以实现多态。做法如下:

    class Person{
    public:
         virtual ~Person()
        {
            cout << "~Person" << endl;
        }
    };
    class Student :public Person
    {
    public:
         ~Student()
        {
            cout << "~Student" << endl;
        }
    };
    
    int main()
    {
    
        Person* p = new Student;
        delete p;
    
        return 0;
    }
    

    在这个例子中,我们定义了一个Person类和一个派生类Student,Person类的析构函数被定义为虚函数。在main函数中,我们用Student类的指针来初始化Person类型的指针,并调用delete删除它。这样做,就能保证在调用delete时,派生类的析构函数也会被调用。

    此时,子类对象被正确地删除,不会造成内存泄漏。子类对象占用的堆区空间大小,取决于子类中新增的成员变量与基类的继承关系。如果不新增成员变量,占用的空间大小和基类相同;如果新增成员变量,占用的空间大小就会增加。