我在练一些继承和虚析构函数和我不断收到运行我的代码,在子类的析构函数正常工作,但超类的析构函数只是不会正常工作后抛出,出现异常的问题。
我想我对析构函数有一些误解,因为每次我看到虚拟析构函数时,命令“ delete”实际上是在析构函数之外使用的,但是,如果我这样做了,那么创建析构函数的意义何在?< / p>
#include <iostream>
template <class T>
class List
{
protected:
T *data;
public:
List()
{
data = new T[5];
std::cout << "List constructor!";
}
virtual void putIn()
{
for (int i = 0; i < 4; i++)
std::cin >> data[i];
}
virtual void printOut()
{
for (int i = 0; i < 5; i++)
std::cout << data[i] << std::endl;
}
virtual ~List()
{
delete[]data;
std::cout << "List destructor!";
}
};
template <class T>
class League : public List<T>
{
public:
League()
{
data = new T[5];
std::cout << "League constructor!";
}
virtual void putIn()
{
std::cout << "Enter your values:\n";
for (int i = 0; i < 5; i++)
std::cin >> data[i];
}
virtual void printOut()
{
std::cout << "Your values are:\n";
for (int i = 0; i < 5; i++)
std::cout << data[i] << std::endl;
}
~League()
{
delete[]data;
std::cout << "League destructor!";
}
};
int main()
{
List<char> *p;
League<char> leag;
p = &leag;
p ->putIn();
getchar();
getchar();
}
一切正常,但是程序结束时,它说抛出了异常,它指向基类的析构函数。任何帮助表示赞赏!
答案 0 :(得分:2)
崩溃的摘要是:当派生类被破坏时,将调用其析构函数,然后将其基于基类的析构函数调用。派生的析构函数调用delete[]data;
,然后基类再次调用delete[]data;
,这是未定义的行为。幸运的是,在这种情况下,导致系统崩溃,所以你知道寻找它。
这个想法是基类拥有data
指针,因此基类应该是要删除它的指针。派生类不拥有该指针,因此不应删除它。
由于这种误解,Dialectius还观察到内存泄漏。构造League
时,将首先调用List
构造函数,并分配内存,然后再调用League
构造函数,其分配不同的内存,从而泄漏内存的第一位。同样,派生类不拥有该指针,因此可能不应该触摸它。派生类应要求基类修改指针。
值得一提的是,您的类违反了The Rule of Three,因此您应该添加复制构造函数和复制赋值运算符以确保类的安全。
答案 1 :(得分:1)
的问题是,data
被删除两次,第一次在~League()
,然后在~List()
。从delete
中删除~League()
。
然后存在内存泄漏问题。 League
对List::data
不负责,但会对其进行初始化。这会导致内存泄漏,因为以前的值将永远丢失并且不会被删除。因此,不要在League
中设置新值,而要使用其他方法告诉List
更改值,然后只有List
负责其成员,并且必须delete[]
设定一个新的前旧的。
答案 2 :(得分:1)
那我为什么需要子析构函数?
就像Dialecticus所说的,在这种情况下您不需要它。假设你要保持你的阵列备份,那么你就必须在子类中像T * childData另一个动态模板领域。现在,最好使用子类的析构函数。