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

C++不可拷贝抽象基类场景下如何动态调用指定派生类update方法

可行实现方案

核心思路是避免对包含虚表指针的完整基类对象执行memcpy,仅同步基类的业务数据成员,通过模板封装不同派生类的调用逻辑,运行时动态选择执行。


方案1:手动同步基类数据(标准兼容,推荐)

如果基类mesh的数据成员是可访问的,直接逐个赋值即可完全规避虚表覆盖问题,完全符合C++标准要求。我们可以预定义所有派生类的调用包装,运行时根据用户输入选择对应的包装函数执行即可。
完整实现代码如下:

#include <iostream>
#include <functional>
using namespace std;

struct mesh
{
    int m = 0;
    virtual void update() = 0;
    
    mesh() {}
    mesh(const mesh&) = delete;
    mesh(mesh&&) = delete;
    mesh& operator=(const mesh&) = delete;
    mesh& operator=(mesh&&) = delete;
    virtual ~mesh(){}
};

struct mesh1 : public mesh
{
    int k = 1;
    virtual void update()
    {
        cout << "mesh1 : " << k << " " << m << endl;
    }
};

struct mesh2 : public mesh
{
    int k = 2;
    virtual void update()
    {
        cout << "mesh2 : " << k << " " << m << endl;
    }
};

// 派生类调用包装模板
template<typename MeshT>
void invoke_mesh_update(mesh& target)
{
    MeshT tmp;
    // 同步基类数据到临时对象
    tmp.m = target.m;
    // 调用对应派生类的update
    tmp.update();
    // 同步修改后的基类数据回原对象
    target.m = tmp.m;
}

struct genMesh : public mesh
{
    int k = 5;
    // 运行时可修改的调用器,支持动态切换派生类实现
    std::function<void(mesh&)> updater = invoke_mesh_update<mesh1>;

    virtual void update()
    {
        cout << "meshGen : " << k << " " << m << endl;
        // 调用用户选择的派生类update逻辑
        updater(*this);
        cout << "meshGen after update : " << k << " " << m << endl;
    }
};

int main()
{
    auto g = new genMesh();
    // 运行时切换为mesh1实现
    g->updater = invoke_mesh_update<mesh1>;
    g->update();
    cout << "===== switch to mesh2 =====" << endl;
    // 运行时切换为mesh2实现
    g->updater = invoke_mesh_update<mesh2>;
    g->update();

    delete g;
    return 0;
}

方案2:跳过虚表指针拷贝数据段(兼容主流编译环境)

如果基类成员较多或不可访问,可以利用GCC、Clang、MSVC等绝大多数编译器的常规内存布局(有虚函数的类开头存储虚表指针,后续存储数据成员),拷贝时跳过虚表指针的长度即可,适配C++11及以上所有标准:

#include <cstring>

void copy_mesh_data(mesh& dst, const mesh& src)
{
    // 跳过开头的虚表指针,仅拷贝后续数据段
    constexpr size_t vptr_size = sizeof(void*);
    static_assert(sizeof(mesh) > vptr_size, "mesh类无数据成员");
    memcpy(reinterpret_cast<char*>(&dst) + vptr_size, 
           reinterpret_cast<const char*>(&src) + vptr_size, 
           sizeof(mesh) - vptr_size);
}

只需将方案1中invoke_mesh_update模板的赋值逻辑替换为上述拷贝函数即可:

template<typename MeshT>
void invoke_mesh_update(mesh& target)
{
    MeshT tmp;
    copy_mesh_data(tmp, target);
    tmp.update();
    copy_mesh_data(target, tmp);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 09:15:02