You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

类型擦除对象的vtable链接错误原因及解决方法

类型擦除类编译链接错误分析与修复

问题背景

我正在为项目实现一个类型擦除类,简化实现代码如下:

#include <iostream>

struct MyClass
{
    struct TypeWrapper
    {
        virtual void print_value() const;
    };

    template<typename ErasedType>
    struct ErasedTypeClass: public TypeWrapper
    {
        ErasedType object;
        ErasedTypeClass(ErasedType init_val): object(init_val) {}

        void print_value() const override
        {
            std::cout << object << '\n';
        }
    };

    TypeWrapper wrapper;
};

int main()
{
    MyClass class_object_int;
    class_object_int.wrapper = MyClass::ErasedTypeClass<int>(5);

    MyClass class_object_float;
    class_object_float.wrapper = MyClass::ErasedTypeClass<float>(10.0f);
}

使用g++ -std=c++17编译时,编译环节无问题,但链接阶段抛出如下错误:

/cefs/ee/eed41a3e34266cd09176ffa5_gcc-trunk-20260515/bin/../lib/gcc/x86_64-linux-gnu/17.0.0/../../../../x86_64-linux-gnu/bin/ld: /tmp/cclA5P5w.o: in function `main':
<source>:27:(.text+0x9): undefined reference to `vtable for MyClass::TypeWrapper'
/cefs/ee/eed41a3e34266cd09176ffa5_gcc-trunk-20260515/bin/../lib/gcc/x86_64-linux-gnu/17.0.0/../../../../x86_64-linux-gnu/bin/ld: <source>:30:(.text+0x36): undefined reference to `vtable for MyClass::TypeWrapper'
/cefs/ee/eed41a3e34266cd09176ffa5_gcc-trunk-20260515/bin/../lib/gcc/x86_64-linux-gnu/17.0.0/../../../../x86_64-linux-gnu/bin/ld: /tmp/cclA5P5w.o: in function `MyClass::TypeWrapper::TypeWrapper()':
<source>:5:(.text._ZN7MyClass11TypeWrapperC2Ev[_ZN7MyClass11TypeWrapperC5Ev]+0x9): undefined reference to `vtable for MyClass::TypeWrapper'
/cefs/ee/eed41a3e34266cd09176ffa5_gcc-trunk-20260515/bin/../lib/gcc/x86_64-linux-gnu/17.0.0/../../../../x86_64-linux-gnu/bin/ld: /tmp/cclA5P5w.o:(.rodata._ZTIN7MyClass15ErasedTypeClassIfEE[_ZTIN7MyClass15ErasedTypeClassIfEE]+0x10): undefined reference to `typeinfo for MyClass::TypeWrapper'
/cefs/ee/eed41a3e34266cd09176ffa5_gcc-trunk-20260515/bin/../lib/gcc/x86_64-linux-gnu/17.0.0/../../../../x86_64-linux-gnu/bin/ld: /tmp/cclA5P5w.o:(.rodata._ZTIN7MyClass15ErasedTypeClassIiEE[_ZTIN7MyClass15ErasedTypeClassIiEE]+0x10): undefined reference to `typeinfo for MyClass::TypeWrapper'
collect2: error: ld returned 1 exit status
ASM generation compiler returned: 1
/cefs/ee/eed41a3e34266cd09176ffa5_gcc-trunk-20260515/bin/../lib/gcc/x86_64-linux-gnu/17.0.0/../../../../x86_64-linux-gnu/bin/ld: /tmp/cc8zjuKh.o: in function `main':
<source>:27:(.text+0x9): undefined reference to `vtable for MyClass::TypeWrapper'
/cefs/ee/eed41a3e34266cd09176ffa5_gcc-trunk-20260515/bin/../lib/gcc/x86_64-linux-gnu/17.0.0/../../../../x86_64-linux-gnu/bin/ld: <source>:30:(.text+0x36): undefined reference to `vtable for MyClass::TypeWrapper'
/cefs/ee/eed41a3e34266cd09176ffa5_gcc-trunk-20260515/bin/../lib/gcc/x86_64-linux-gnu/17.0.0/../../../../x86_64-linux-gnu/bin/ld: /tmp/cc8zjuKh.o: in function `MyClass::TypeWrapper::TypeWrapper()':
<source>:5:(.text._ZN7MyClass11TypeWrapperC2Ev[_ZN7MyClass11TypeWrapperC5Ev]+0x9): undefined reference to `vtable for MyClass::TypeWrapper'
/cefs/ee/eed41a3e34266cd09176ffa5_gcc-trunk-20260515/bin/../lib/gcc/x86_64-linux-gnu/17.0.0/../../../../x86_64-linux-gnu/bin/ld: /tmp/cc8zjuKh.o:(.rodata._ZTIN7MyClass15ErasedTypeClassIfEE[_ZTIN7MyClass15ErasedTypeClassIfEE]+0x10): undefined reference to `typeinfo for MyClass::TypeWrapper'
/cefs/ee/eed41a3e34266cd09176ffa5_gcc-trunk-20260515/bin/../lib/gcc/x86_64-linux-gnu/17.0.0/../../../../x86_64-linux-gnu/bin/ld: /tmp/cc8zjuKh.o:(.rodata._ZTIN7MyClass15ErasedTypeClassIiEE[_ZTIN7MyClass15ErasedTypeClassIiEE]+0x10): undefined reference to `typeinfo for MyClass::TypeWrapper'
collect2: error: ld returned 1 exit status
Execution build compiler returned: 1
Build failed

请问错误信息"undefined reference to 'vtable for MyClass::TypeWrapper'"具体含义是什么,该如何修复此问题?


错误含义解释

undefined reference to 'vtable for MyClass::TypeWrapper'表示链接器找不到TypeWrapper类的虚函数表(vtable)。在C++中,包含虚函数的类会由编译器生成虚函数表,用于实现动态多态机制。如果类中的非纯虚函数只有声明没有定义,编译器无法生成完整的虚函数表,链接阶段就会触发这个错误。

你的代码中TypeWrapper的print_value函数仅声明未定义,且未标记为纯虚函数,导致编译器无法生成该类的虚函数表。

修复方案

方案1:将print_value声明为纯虚函数

把TypeWrapper的虚函数改为纯虚函数,使其成为抽象基类,此时编译器不需要为它生成完整虚函数表,由派生类提供具体实现即可:

struct TypeWrapper
{
    virtual void print_value() const = 0; // 纯虚函数,强制派生类实现
};

方案2:为print_value提供默认实现

若不想让TypeWrapper成为抽象基类,可以给该虚函数添加空的默认实现:

struct TypeWrapper
{
    virtual void print_value() const {} // 空默认实现
};

额外问题:对象切片

修复链接错误后,代码仍存在对象切片问题:

class_object_int.wrapper = MyClass::ErasedTypeClass<int>(5);

派生类对象赋值给基类对象时,派生类的额外成员(如object)会被切割丢失,后续调用print_value会触发未定义行为。

解决此问题需使用指针或智能指针存储派生类对象,修改MyClass的成员定义如下:

#include <iostream>
#include <memory>

struct MyClass
{
    struct TypeWrapper
    {
        virtual void print_value() const = 0;
        virtual ~TypeWrapper() = default; // 基类必须声明虚析构函数,避免内存泄漏
    };

    template<typename ErasedType>
    struct ErasedTypeClass: public TypeWrapper
    {
        ErasedType object;
        ErasedTypeClass(ErasedType init_val): object(init_val) {}

        void print_value() const override
        {
            std::cout << object << '\n';
        }
    };

    std::unique_ptr<TypeWrapper> wrapper; // 使用智能指针存储派生类对象
};

int main()
{
    MyClass class_object_int;
    class_object_int.wrapper = std::make_unique<MyClass::ErasedTypeClass<int>>(5);
    class_object_int.wrapper->print_value(); // 输出5

    MyClass class_object_float;
    class_object_float.wrapper = std::make_unique<MyClass::ErasedTypeClass<float>>(10.0f);
    class_object_float.wrapper->print_value(); // 输出10
}

这样就能完整保留派生类对象信息,实现类型擦除的预期效果。

内容的提问来源于stack exchange,提问作者Setu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.02 01:47:27