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

如何规避C++多态包装器派生类复制时的间接层?

实现值语义多态包装类的间接层优化问题

我希望实现一个具有值语义的多态类型包装类,对标提案P0201和P3019的设计:对于基类Base及其派生类Derived,包装器Poly<Base>可以容纳Derived对象,且复制Poly<Base>时会创建Derived的深拷贝。

核心控制块基础实现

核心思路是采用可克隆的控制块,简化后的代码如下:

struct BaseControl<BaseType>
{
   virtual auto clone() -> BaseControl<BaseType>* = 0;
   virtual auto object() -> BaseType* = 0;
};

struct Control<BaseType, DerivedType> : public BaseControl<BaseType>
{
   auto clone() -> BaseControl<BaseType>* {return new Control(*this);}
   auto object() -> BaseType* {return std::addressof(object);}
   
   DerivedType object;
};

struct Poly<BaseType> 
{
   Poly(InPlace<DerivedType>) : control{new Control<BaseType, DerivedType>()} {}
   Poly(Poly const& other) : control{other.control->clone()} {}

   BaseControl<BaseType>* control;
};

为简洁起见,代码经过简化,忽略缺失的模板关键字、特殊成员函数、内存泄漏等问题

P0201的派生类构造方案及痛点

P0201允许从Poly<Derived>构造Poly<Base>,参考实现通过委托控制块完成:

struct DelegatingControl<BaseType, DerivedType> : public BaseControl<BaseType>
{
   auto clone() -> BaseControl<BaseType>* {return new DelegatingControl(subControl->clone());}
   auto object() -> BaseType* {return subControl->object();}
   
   BaseControl<DerivedType>* subControl;
};

但这种实现会导致每次从派生类包装器复制/移动时,引入额外的间接层,我想知道是否有办法规避这个问题。

优化尝试:移除BaseControl中的BaseType

我的思路是剥离BaseControl中的BaseType参数,重新设计控制块:

struct BaseControl
{
   virtual auto clone() -> BaseControl* = 0;
   virtual auto object_address() -> void* = 0;
};

struct Control<DerivedType> : public BaseControl
{
   auto clone() -> BaseControl* {return new Control<DerivedType>(*this);}
   auto object_address() -> void* {return std::addressof(object);}
   
   DerivedType object;
};

但克隆后如何正确访问对象成为难题,需要计算从BaseControl到目标类型的偏移量,对应的Poly实现如下:

struct Poly<BaseType>
{
   Poly(InPlace<DerivedType>) :
      control{new Control<DerivedType>()}, 
      ptr{static_cast<DerivedType*>(control->object_address())} 
   {}

   BaseControl* control;
   BaseType* ptr;
};

// 从Poly<Derived>移动构造的实现很简单
Poly<BaseType>(Poly<DerivedType> other)
{
   control = std::exchange(other.control, nullptr);
   ptr = std::exchange(other.ptr, nullptr);
}

// 复制构造的实现存在疑问
Poly<BaseType>(Poly<BaseType> const& other)
{
   control = other.control->clone();
   auto offset = (void*) other.ptr - other.control->object_address(); // 是否允许?
   ptr = (BaseType*)(control->object_address() + offset);             // 是否允许?
}

除了void*算术运算本身不被标准允许(可转换为unsigned char*规避),我不确定这段代码是否会引入未定义/未指定行为。

其他备选方案的局限

  • 若将BaseType*替换为成员指针BaseType BaseControl::*,标准不允许将其转换为Derived BaseControl::*,会破坏从Poly<Derived>的构造逻辑。
  • 要求所有类型派生自某个虚基类,这种方案不够优雅,侵入性太强。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 20:53:21