【发布时间】:2020-10-15 21:22:07
【问题描述】:
我有一个代表抽象数据类型“Bag”的接口。为了实现这种抽象数据类型,我使用了基于数组和基于链接的实现。
这里是类的定义
编辑正如您所指出的,我已将虚拟析构函数添加到我的基类
template<class ItemType>
class BagInterface{
public:
virtual int getCurrentSize() const = 0;
virtual bool isEmpty() const = 0;
virtual bool add(const ItemType& newEntry) = 0;
virtual bool remove(const ItemType& anEntry) = 0;
virtual int getFrequencyOf(const ItemType& anEntry) const = 0;
virtual bool contains (const ItemType& anEntry) const = 0;
virtual void clear() = 0;
virtual vector<ItemType> toVector() const = 0;
virtual ~BagInterface() = default;
};
#endif /* BagInterface_hpp */
我的 2 个派生类在他们的路上实现了这些方法。
我的基于链接的实现使用虚拟析构函数,因为与基于数组的实现不同,它动态分配内存,最终它必须使用“删除”关键字删除实例,以避免内存泄漏。
链接包的析构函数
template<class ItemType>
LinkedBag<ItemType>::~LinkedBag(){
clear(); // Clears bag's content.
}
arraybag 的析构函数
template<class ItemType>
ArrayBag<ItemType>::~ArrayBag(){
clear();
}
在所有实施问题之后,我想测试我的 ADT 操作。
我创建了一个函数,它以指针作为输入来表示袋子。
void bagTester(BagInterface<int>* bagPtr){
// do some test }
在我的主要功能中,完成测试后,我想删除我的 bagPtr,因为我已经完成了它,所以是时候删除它了。
int main(){
BagInterface<int>* bagPtr = nullptr;
char userChoice;
cin>> userChoice;
if(userChoice == 'A'){
bagPtr = new ArrayBag<int>(); // Array based implementation
}else if(userChoice == 'L'){
bagPtr = new LinkedBag<int>(); // Link bases implementation
}
bagTester(bagPtr); // test my bag
delete bagPtr; // and now i'm finished with test let's delete the pointer
bagPtr = nullptr; // deallocate
}
**此时我的错误正在发生,编译器会发出警告 -> **
In file included from main.cpp:2:
In file included from ./LinkedBag.hpp:5:
./BagInterface.hpp:36:31: warning: defaulted function definitions are a C++11 extension [-Wc++11-extensions]
virtual ~BagInterface() = default;
^
In file included from main.cpp:4:
./ArrayBag.hpp:28:5: error: exception specification of overriding function is more lax than base version
~ArrayBag();
^
main.cpp:48:22: note: in instantiation of template class 'ArrayBag<int>' requested here
bagPtr = new ArrayBag<int>();
^
./BagInterface.hpp:36:13: note: overridden virtual function is here
virtual ~BagInterface() = default;
^
In file included from main.cpp:2:
./LinkedBag.hpp:25:1: error: exception specification of overriding function is more lax than base version
~LinkedBag();
^
main.cpp:52:22: note: in instantiation of template class 'LinkedBag<int>' requested here
bagPtr = new LinkedBag<int>();
^
./BagInterface.hpp:36:13: note: overridden virtual function is here
virtual ~BagInterface() = default;
^
1 warning and 2 errors generated.
我检查了这个相关主题 -> Suppress delete-non-virtual-dtor warning when using a protected non-virtual destructor
我尝试了其中一项建议,即:
准则 #4:基类析构函数应该是公共的和虚拟的,或者是受保护的和非虚拟的。
并且还尝试向 BagInterface 添加虚拟析构函数,但没有成功。(编辑:我知道我应该添加虚拟析构函数:))
我不明白这个问题,因为两个派生类都有自己的析构函数,arrayBag 有默认析构函数,linkedBag 有虚拟析构函数。
那么,我该如何避免警告呢?
【问题讨论】:
-
"尝试向 BagInterface 添加虚拟析构函数,但没有成功" 让我们以此为起点。您将虚拟析构函数添加到 BagInterface 是因为没有虚拟析构函数是错误的。所以在你添加虚拟析构函数之前的一切都是错误的。现在你有了一个虚拟析构函数,描述你的问题。
-
您意识到现在您会泄漏内存,因为基于链接的实现的析构函数没有通过您的
delete bagPtr调用? -
让我们再试一次。没有虚拟析构函数是错误的。拥有一个虚拟析构函数是正确的。然而,单独拥有一个虚拟析构函数并不能保证正确性。您的代码可能还有其他问题。但是,您不会分享您的错误,因此我们无法判断这些错误是什么。如果您想回答您的问题,您应该实际发布编译器打印的实际错误。 “它没有用”不是有用的信息。我们可以猜测它没有工作。否则你可能不会在这里。
-
明确一点:如果程序通过指向基类的指针删除派生类型的对象,而基类没有虚析构函数,则程序的行为是未定义的。
-
在编程中你会发现一件事是有时修正一个错误会揭示更多错误。不要假设编译的代码比未编译的代码更接近正确。编写可编译且逻辑不正确的代码非常容易。此外,有时您可以添加一个非常需要的分号或右大括号,然后看到错误列表从一个错误增加到数百个,因为编译器现在可以解释更多代码并对其正确性进行注释。做正确的事,然后将发现的任何“新”错误排除在外。
标签: c++ pointers abstract-class abstract-data-type