我对以下代码有疑问:
#include <iostream>
#include <boost/scoped_ptr.hpp>
class Interface
{
};
class A : public Interface
{
public:
A() { std::cout << "A()" << std::endl; }
virtual ~A() { std::cout << "~A()" << std::endl; }
};
Interface* get_a()
{
A* a = new A;
return a;
}
int main()
{
{
std::cout << "1" << std::endl;
boost::scoped_ptr<Interface> x(get_a());
std::cout << "2" << std::endl;
}
std::cout << "3" << std::endl;
}
它会创建以下输出:
1
A()
2
3
如您所见,它不会调用A的析构函数。 我看到获取A的析构函数的唯一方法是为Interface类添加一个析构函数,如下所示:
virtual ~Interface() { }
但我真的想避免在我的Interface类中使用任何实现而且virtual ~Interface() = 0;
不起作用(产生一些链接器错误抱怨~Interface()
的非现有实现。
所以我的问题是:为了使析构函数被调用,我需要更改什么,但是(如果可能的话)将接口作为接口(仅抽象方法)。
答案 0 :(得分:5)
您必须在基类中定义虚拟析构函数,否则您将不会获得多态行为。
更重要的是,你会得到未定义的行为; §5.3.5/ 3:
如果操作数的静态类型与其动态类型不同,则静态类型应为操作数的动态类型的基类,而静态类型应具有虚拟析构函数或行为未定义
强调我的。
我认为最好的是这个:
class Interface
{
public:
virtual ~Interface(void) = 0;
};
inline Interface::~Interface(void) {}
与实现驻留在源文件中的解决方案不同,编译器可以轻松地内联它。 (说到这个,这个解决方案甚至不要求你有一个。)它也让这个类纯粹是虚拟的。
答案 1 :(得分:2)
如果要通过指向基类接口类型的指针删除派生类对象,则必须声明析构函数virtual
,并且析构函数必须具有实现。
你仍然可以宣称它是纯虚拟的:
class Interface
{
public:
virtual ~Interface() = 0;
};
inline Interface::~Interface() { }
答案 2 :(得分:2)
您需要定义Interface析构函数的纯虚拟版本,但您还需要定义析构函数的主体。这是C ++中的一种奇怪的情况,即使函数是虚函数,也必须定义它,因为在调用析构函数之后,也会调用实例析构函数。
因此,正确的答案是:
virtual ~Interface() = 0;
后来,在一个cpp文件中:
Interface::~Interface() {}