如何让拷贝构造函数同步拷贝虚表?C++标准实现方案问询
问题:基类拷贝构造中原地初始化派生类虚表
现有类继承结构 I <- A、I <- B,要求基类I的拷贝构造函数能够原地初始化派生类的虚表,已知sizeof(A) == sizeof(B) == sizeof(I),优先避免动态内存分配,允许使用placement new。
原代码
#include <iostream> using namespace std; class B; class I { public: virtual ~I() { cout << "~I()\n"; } I() { cout << "I ctor\n"; } virtual void print() { cout << "I::print()\n"; } I(const I& clone); }; class A : public I { public: ~A() override { cout << "~A()\n"; } void print() override { cout << "A::print()\n"; } }; class B : public I { public: B() { cout << "B ctor\n"; } B(const B& clone) { cout << "B copy ctor\n"; } ~B() override { cout << "~B()\n"; } void print() override { cout << "B::print()\n"; } }; I::I(const I& clone) { cout << "B copy ctor 2\n"; B* b = dynamic_cast<B*>((I*)&clone); if (b != nullptr) { this->~I(); new (this) B(*b); } } class T { public: I GetA() { return B(); } }; int main() { cout << "main() ->\n"; T t; { cout << "- GetA()\n"; I i = t.GetA(); i.print(); cout << "- before scope end\n"; } cout << "- main scope\n"; cout << "<- main()\n"; }
当前输出
main() -> - GetA() I ctor B ctor B copy ctor 2 ~I() I ctor B copy ctor ~B() ~I() I::print() - before scope end ~I() - main scope <- main()
期望输出
main() -> - GetA() I ctor B ctor B copy ctor 2 ~I() I ctor B copy ctor ~B() ~I() B::print() <--- changed - before scope end ~B() <--- added ~I() - main scope <- main()
解决方案
原代码核心问题是返回值切片导致源对象丢失派生类类型信息,且依赖未定义行为的dynamic_cast判断类型。通过给基类添加虚克隆方法,可安全实现原地构造派生类对象。
修改后的代码:
#include <iostream> using namespace std; class I { public: virtual ~I() { cout << "~I()\n"; } I() { cout << "I ctor\n"; } virtual void print() { cout << "I::print()\n"; } I(const I& clone); // 纯虚方法:将当前对象拷贝到指定内存地址 virtual void clone_to(void* dest) const = 0; }; class A : public I { public: ~A() override { cout << "~A()\n"; } void print() override { cout << "A::print()\n"; } void clone_to(void* dest) const override { new (dest) A(*this); } }; class B : public I { public: B() { cout << "B ctor\n"; } B(const B& clone) { cout << "B copy ctor\n"; } ~B() override { cout << "~B()\n"; } void print() override { cout << "B::print()\n"; } void clone_to(void* dest) const override { new (dest) B(*this); } }; I::I(const I& clone) { cout << "I copy ctor\n"; // 销毁默认构造的基类对象 this->~I(); // 调用派生类的clone_to,原地构造对应类型的拷贝 clone.clone_to(this); } class T { public: I GetA() { return B(); } }; int main() { cout << "main() ->\n"; T t; { cout << "- GetA()\n"; I i = t.GetA(); i.print(); cout << "- before scope end\n"; } cout << "- main scope\n"; cout << "<- main()\n"; }
修改说明
- 添加虚克隆方法:在基类
I中定义纯虚方法clone_to,要求派生类实现该方法,完成自身对象的原地拷贝构造。 - 修改基类拷贝构造:先销毁默认构造的
I对象,再调用源对象的clone_to方法,在当前内存位置原地构造派生类对象,确保虚表被正确初始化。 - 派生类实现克隆逻辑:
A和B分别实现clone_to,使用placement new在指定内存地址创建自身类型的拷贝对象。
运行修改后的代码,输出将符合期望:
main() -> - GetA() I ctor B ctor I copy ctor ~I() B copy ctor ~B() ~I() B::print() - before scope end ~B() ~I() - main scope <- main()
内容的提问来源于stack exchange,提问作者TarmoPikaro
相关产品推荐
相关产品推荐

