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
相关产品推荐
相关产品推荐

