我很难在这里决定删除派生类的最佳方法。我目前有以下布局:
class Tag {
// Stuff
// [...]
void releaseMemory(Tag *t);
};
class TagByte : public Tag { /* [...] */ };
class TagShort : public Tag { /* [...] */ };
Tag::releaseMemory(Tag *t) {
switch (t->getType()) {
case TAG_BYTE: delete (TagByte *)t; return;
case TAG_SHORT: delete (TagShort *)t; return;
// [...] many more
}
}
我这样做的原因是有更复杂的标签,如TagCompound
,它们将包含不同类型的标签,所有标签都存储为Tag *
。在析构函数~TagCompound
,~TagList
内,我会在每个标记上调用Tag::releaseMemory();
,因为delete
上的Tag *
只会释放Tag
而不会实际的TagWhatever
,从而导致内存泄漏。
我想到的另一个选择是为每个派生类添加一个新的虚拟方法,因此Tag
的每个孩子都拥有它自己的releaseMemory()
而不是超类中的一个。
然后我想知道我是否已经在设计级别上开始变坏,假设传递到复杂类型TagCompound
和TagList
的所有内容都是堆对象我也找不到更好的解决方案,因为整个构造是解析器的一部分,看起来像这样(只是二进制而不是冗长):
TAG_Compound("Root"): 4 entries
{
TAG_String("Name"): Test
TAG_Short("SomeNumber"): 21
TAG_Double("..."): 9000.5
TAG_Compound("Eek!"): 2 entries
{
TAG_String("Marco"): Polo
TAG_List("Names"): 3 entries of type String
{
TAG_String: Hello
TAG_String: World
TAG_String: Segfault
}
}
}
在运行时动态读取它并不能很好地与堆栈上的实例一起使用。
我能做些什么......我不知道......优雅?
答案 0 :(得分:5)
通常,您只需declare a virtual destructor in the base class。这对堆栈和堆分配都很好。在多态删除的情况下,编译器会计算出真实类型并调用其析构函数。
答案 1 :(得分:1)
这种设计确实打破了封装的想法。 Tag永远不会知道TagByte存在。 Tag的析构函数应该被标记为虚拟,就像每个派生类的析构函数一样。在适当的析构函数中释放每个级别的已分配变量。在销毁时,一切都将以正确的顺序清理,没有内存泄漏。我的感觉是这个设计从一开始就很糟糕,你应该阅读析构函数和继承。
答案 2 :(得分:1)
C ++实际上为此提供了非常优雅的解决方案 - 虚拟析构函数。更重要的是,每种多态类型都应该有一种。 GCC甚至对此-Wnon-virtual-dtor
有警告级别。