【问题标题】:Where should the pure virtual destructor be declared?纯虚析构函数应该在哪里声明?
【发布时间】:2011-09-04 17:03:31
【问题描述】:

编辑:显然这个问题的表述不够清楚。我遇到的问题是,当在标头中定义析构函数时,它会被添加到多个 .obj 文件中,并且链接器会抱怨。实际问题是:

当我将析构函数添加到 DLL 项目中的 CPP 文件并使用动态加载的 dll 和接口头文件时,是否仍会调用基本析构函数以防止内存泄漏?

我正在使用 MSVC 10.0 并且有一个实现接口的 DLL 项目。接口是一个抽象(纯虚拟)基类。这个想法是标题与库的动态加载一起使用。因此,我使用了纯虚析构函数来确保调用基类中的析构函数。这是解释这一点的示例代码:

//ISplitter.h
#pragma once

struct param {
    int something;
}

class ISplitter {
public:
    virtual ~ISplitter() = 0;
    virtual void useful() = 0;
}

ISplitter::~ISplitter() {
    /* Make sure base class destructor gets called */
}

以及主要的实现头

//CSplitter.h
#pragma once
#include "CHelper.h"
#include "ISplitter.h"


class CSplitter : public ISplitter {
private:
    CHelper hlp;
public:
    ~CSplitter();
    void useful();
}

一些帮助类

//CHelper.h
#pragma once
#include "ISplitter.h" // I need the struct

// Class definition should go here but is irrelevant

现在的问题是链接器生成一个错误,告诉我析构函数:ISplitter::~ISplitter(void) 已被多次声明,系统将无法构建。 错误:

CHelper.obj : error LNK2005: "public: virtual __cdecl ISplitter::~ISplitter(void)" (??1ISplitter@@UEAA@XZ) already defined in CSplitter.obj

解决此问题的正确方法是什么?我已将析构函数放在 ISplitter.cpp 中,但我担心如果我动态加载库并将基类向上转换为 ISplitter,这可能不起作用。

【问题讨论】:

  • 请贴出真实代码。答案是将析构函数定义移动到一个.cpp文件中。
  • Pure virtual destructor in C++ 的可能重复项
  • @Neil:或者首先使析构函数不是纯虚拟的。为什么不只是一个空的虚拟析构函数?
  • @Wouter 我们不需要查看原始代码,但我们需要查看说明问题的真实 C++ 代码。例如,这里ISplitter::ISplitter() 我假设缺少~
  • @Neil:我很抱歉,它遗漏了这一点,这是一个严重错误。道歉并修复。

标签: c++ memory-leaks linker-errors virtual-destructor


【解决方案1】:

Sharptooth 的答案是正确的,因为您必须为纯虚拟析构函数 (see this GotW) 提供定义。但是你不能写是错误的

virtual ~A() = 0 {};

根据标准中的这个子句(虽然很多编译器都支持这个扩展)

C++03 的第 10.4 条第 2 段 告诉我们什么是抽象类,并附带说明以下内容:

[注意:函数声明不能​​同时提供纯说明符和定义 ——尾注] [例子:

struct C {
virtual void f() = 0 { }; // ill-formed
};

——结束示例]

详情请见this question of mine

【讨论】:

    【解决方案2】:

    问题是基类析构函数总是被调用——但是在这种情况下,你已经把它变成了纯虚拟的,所以它不存在。使析构函数成为纯虚拟的唯一原因是在没有其他成员时强制类是抽象的。在所有情况下都需要定义类的析构函数。

    编辑:我误读了您的代码。只需虚拟内联定义析构函数即可。

    virtual ~ISplitter() {}

    这里不需要任何纯虚拟成员,因为您已经有其他纯虚拟成员了。

    【讨论】:

    • 它确实存在,因此存在多定义错误,尽管这在他的“伪代码”中并不明显。
    • @Neil:啊,我明白了。感谢您澄清这一点。
    • 我相信这是我更喜欢的,更干净,我相信它会一直存在。所以我接受这个答案。
    • +1 表示“只需定义内联的析构函数”,但我还不能投票。他还可以通过使用 inline 限定析构函数的外联定义来使定义内联。
    • 我认为根据优化设置对 inline 关键字的处理方式不同
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-19
    • 2013-01-08
    • 1970-01-01
    • 1970-01-01
    • 2011-03-31
    • 2012-07-14
    • 1970-01-01
    相关资源
    最近更新 更多