代码之家  ›  专栏  ›  技术社区  ›  Greg D

为什么这个虚拟析构函数会触发一个未解析的外部事件?

  •  15
  • Greg D  · 技术社区  · 14 年前

    考虑以下几点:

    X.h.:

    class X
    {
        X();
        virtual ~X();
    };
    

    X.cpp公司:

    #include "X.h"
    
    X::X()
    {}
    

    错误1错误LNK2001:未解析的外部符号“private:virtual\u thiscall X::~X(void)”(??1倍@@EAE@XZ公司)

    但是,小的修改会导致成功的构建:

    X.h.:

    class X
    {
        inline X(); // Now inlined, and everything builds
        virtual ~X();
    };
    

    X.h.:

    class X
    {
        X();
        ~X(); // No longer virtual, and everything builds
    };
    

    或者,也许更有趣的是,我为什么要这么做

    7 回复  |  直到 10 年前
        1
  •  23
  •   Community CDub    4 年前

    你有构造函数的代码。
    因此它将构造函数构建到对象文件中。构造函数需要将析构函数的地址放入虚拟表中,因为它找不到该地址,因此无法生成构造函数。

    情形2:(内联构造函数)

    编译器决定不需要构建构造函数(因为它将被内联)。

    如果你实例化一个X类型的对象,它会再次抱怨。

    情形3:(非虚拟析构函数)

    构建构造函数不需要析构函数的地址。
    所以它不抱怨。

        2
  •  7
  •   Dima    14 年前

    
    class X
    {
        X();
        virtual ~X() {}
    };
    
        3
  •  5
  •   AnT stands with Russia    14 年前

    在C++函数中必须 定义 如果且仅当他们是 习惯于 在您的程序中(参见3.2/2中的ODR)。一般来说,非虚函数是 习惯于 如果它们是从可能的求值表达式调用的。无条件地考虑任何非纯虚函数 习惯于 . 当[非虚拟]特殊成员函数 在语言标准的专用位置定义。等等。

    • 在你的 第一 习惯于 在你的程序里。这反过来意味着 定义 需要那个析构函数。您未能提供定义,因此编译器报告了一个错误。

    • 在你的 使用 程序中的析构函数,不需要定义,代码可以编译(有关构成析构函数的详细说明,请参见12.4) 使用 一个析构函数)。

    • 在你的 第二

        4
  •  2
  •   Community CDub    7 年前

    是什么原因导致未解决的外部问题 或者当.ctor没有内联时?

    …很简单,你没有定义析构函数。

    现在你的第二个问题更有趣了:

    为什么我得不到一个悬而未决的问题 非虚拟的,或者如果我内联 建造师?

    X 的析构函数,因为您从未实例化

    class X
    {
    public:
        X();
         ~X();
    };
    
    X::X() {};
    
    int main()
    {
        X x;
        return 0;
    }
    

    但如果你不加评论 X x; 正如您所观察到的,它将编译得很好。

    virtual . 我在这里猜测,但我相信原因是,既然你有一个虚拟的析构函数, vtable 需要每个虚拟函数的地址。你还没有实现 X::~X

    为什么编译器不直接抛出 当它离开的时候 不是多态类?更多的猜测。但我认为原因是即使你没有直接实例化 ,不能确定代码中没有任何地方 活着,伪装成别的东西。例如,考虑一个抽象基类。在这种情况下,您永远不会实例化 Base 直接和代码 Derived 可能在一个完全独立的翻译单元里。因此,当编译器到达这个多态类时,它不能丢弃它,即使它不知道您实例化了它。

        5
  •  1
  •   Lou Franco    14 年前

    这些还不是一个完整的程序(甚至不是一个完整的DLL)。当您得到错误时,您实际上得到了帮助,因为没有~X()的定义,X是不可用的

    这意味着这个特定的编译器实例在某些情况下需要一个定义。即使它编译了,也什么都不做。

        6
  •  1
  •   Chubsdad    14 年前

    在该类中声明为纯(10.4),或 两者都有;但不需要诊断 (3.2)."

    GCC给出了下面这样的错误,这再次强烈地暗示了(至少对我来说)实现虚拟函数的非标准实现细节

    /home/OyXDcE/ccS7g3Vl.o:在函数中 X::X()': prog.cpp:(.text+0x6): undefined reference to /home/OyXDcE/ccS7g3Vl.o:在函数中 X::X()': prog.cpp:(.text+0x16): undefined reference to collect2:ld返回1退出状态

        7
  •  0
  •   Steve Townsend    14 年前

    你可能会侥幸逃脱这一点,因为constr和dest都是私有的-如果在你的构建中没有对类X的其他引用,那么编译器可能会推断dest不是必需的,所以缺少定义也没什么大不了的。

    这并没有向我解释为什么案例1失败,而2和3构建正常。想知道如果两者都被公开会发生什么?