如何只为派生类调用析构函数?

时间:2017-11-21 16:37:46

标签: c++ c++11 inheritance polymorphism

我有两个类Base和Derived。当我在main中只创建一个Derived对象并写入返回0时,我看到,基类的析构函数和派生类的析构函数都被调用。

因此我犯了一个错误。基类析构函数用于删除已由派生类析构函数删除的内存。

所以,我不想调用基类的析构函数。我只想调用派生类析构函数,因为我只创建了派生类对象。

这是我的代码和我的错误。

#include <new>
#include <iostream>

using namespace std;

class Base {
public:
    Base(){
        size=4;
        arr= new int[size];
        for(int i=0;i<size;i++){
            arr[i]=0;
        }
    }
    ~Base(){
         cout<<"Base class destructor called"<<endl;
         delete[] arr;
    }
protected:
    int *arr;
    int size;
};

class Derived : public Base {
public:
    Derived(){
        size=5;
        arr= new int[size];
        for(int i=0;i<size;i++){
            arr[i]=0;
        }
    }
    ~Derived(){
        cout<<"Derived class destructor called"<<endl;
        delete[] arr;
    }

};

int main(){
    Derived derivedObject;
    return 0;
}

我的错误是,

Derived class destructor called
Base class destructor called
*** Error in `./exe': double free or corruption (fasttop): 0x0000000001f20c40 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f2d65d147e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f2d65d1d37a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f2d65d2153c]
./exe[0x400c31]
./exe[0x400d31]
./exe[0x400afb]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f2d65cbd830]
./exe[0x4009f9]
======= Memory map: ========
00400000-00402000 r-xp 00000000 08:06 1183568                            /home/burhan/Desktop/hw5-1/exe
00601000-00602000 r--p 00001000 08:06 1183568                            /home/burhan/Desktop/hw5-1/exe
00602000-00603000 rw-p 00002000 08:06 1183568                            /home/burhan/Desktop/hw5-1/exe
01f0f000-01f41000 rw-p 00000000 00:00 0                                  [heap]
7f2d60000000-7f2d60021000 rw-p 00000000 00:00 0 
7f2d60021000-7f2d64000000 ---p 00000000 00:00 0 
7f2d65994000-7f2d65a9c000 r-xp 00000000 08:06 2110523                    /lib/x86_64-linux-gnu/libm-2.23.so
7f2d65a9c000-7f2d65c9b000 ---p 00108000 08:06 2110523                    /lib/x86_64-linux-gnu/libm-2.23.so
7f2d65c9b000-7f2d65c9c000 r--p 00107000 08:06 2110523                    /lib/x86_64-linux-gnu/libm-2.23.so
7f2d65c9c000-7f2d65c9d000 rw-p 00108000 08:06 2110523                    /lib/x86_64-linux-gnu/libm-2.23.so
7f2d65c9d000-7f2d65e5d000 r-xp 00000000 08:06 2110528                    /lib/x86_64-linux-gnu/libc-2.23.so
7f2d65e5d000-7f2d6605d000 ---p 001c0000 08:06 2110528                    /lib/x86_64-linux-gnu/libc-2.23.so
7f2d6605d000-7f2d66061000 r--p 001c0000 08:06 2110528                    /lib/x86_64-linux-gnu/libc-2.23.so
7f2d66061000-7f2d66063000 rw-p 001c4000 08:06 2110528                    /lib/x86_64-linux-gnu/libc-2.23.so
7f2d66063000-7f2d66067000 rw-p 00000000 00:00 0 
7f2d66067000-7f2d6607d000 r-xp 00000000 08:06 2102075                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f2d6607d000-7f2d6627c000 ---p 00016000 08:06 2102075                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f2d6627c000-7f2d6627d000 rw-p 00015000 08:06 2102075                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f2d6627d000-7f2d663ef000 r-xp 00000000 08:06 1966485                    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f2d663ef000-7f2d665ef000 ---p 00172000 08:06 1966485                    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f2d665ef000-7f2d665f9000 r--p 00172000 08:06 1966485                    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f2d665f9000-7f2d665fb000 rw-p 0017c000 08:06 1966485                    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f2d665fb000-7f2d665ff000 rw-p 00000000 00:00 0 
7f2d665ff000-7f2d66625000 r-xp 00000000 08:06 2110506                    /lib/x86_64-linux-gnu/ld-2.23.so
7f2d667ff000-7f2d66804000 rw-p 00000000 00:00 0 
7f2d66821000-7f2d66824000 rw-p 00000000 00:00 0 
7f2d66824000-7f2d66825000 r--p 00025000 08:06 2110506                    /lib/x86_64-linux-gnu/ld-2.23.so
7f2d66825000-7f2d66826000 rw-p 00026000 08:06 2110506                    /lib/x86_64-linux-gnu/ld-2.23.so
7f2d66826000-7f2d66827000 rw-p 00000000 00:00 0 
7ffe7cad2000-7ffe7caf3000 rw-p 00000000 00:00 0                          [stack]
7ffe7cb04000-7ffe7cb06000 r--p 00000000 00:00 0                          [vvar]
7ffe7cb06000-7ffe7cb08000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted (core dumped)

3 个答案:

答案 0 :(得分:1)

  

当我在main中只创建了一个Derived对象并且写了返回0时,我看到了,base的解构函数和派生的都被称为

是的,Derived对象包含Base类型的基类子对象。

基类子对象负责它自己的初始化和销毁​​。因此,您应该将基类对象状态的清理委托给基类析构函数。

类似地,您应该将基类对象的构造委托给基类构造函数:这是已经隐式发生,因此派生类构造函数会泄漏内存。

答案 1 :(得分:0)

class Base {
protected:
  Base(std::size_t n) {
    size=n;
    arr= new int[size];
    for(int i=0;i<size;i++){
      arr[i]=0;
    }
  }
public:
  Base():Base(4){}
  ~Base(){
     std::cout<<"Base class destructor called\n";
     delete[] arr;
  }
protected:
  int *arr;
  int size;
};

class Derived : public Base {
public:
  Derived():Base(5){}
  ~Derived(){
    std::cout<<"Derived class destructor called\n";
  }
};

这就是你应该怎么做的。

Base提供了一个受保护的构造函数,允许它构造一个大小。

Base()委托给那个构造函数。

Derived()也可以。

Base管理内存,Derived只更改默认大小。

您不能使用C ++类继承,也不能让派生类构造函数调用基类构造函数,也不能让派生析构函数不调用基类析构函数。

答案 2 :(得分:0)

当你赋予一个对象生命时,该对象是由所谓的 costructor链构建的;这意味着如果你想给Derived类型的对象赋予生命,首先必须对Base类型的对象进行构造 每个costructor都必须初始化它所属的类中的成员,因此Base将初始化Base的成员,Derived的costructor将初始化Derived的成员。
同样,当您需要删除Derived对象时,类似的链开始,但方向相反,即从Derived类到Base类。
对象必须逐个拆卸:派生的descrutor必须只删除Derived类中引入的成员,而不是其他成员。相反,删除Base类的成员是Base的类析构函数的唯一责任。
因此,删除Derived的析构函数中的行,删除Base类引入的数组

 delete[] arr;

并将其保留在Base类中。