基于 C++ 策略的设计 : Inheritance vs composition

标签 c++ templates inheritance policy-based-design

在 Meeting C++ 2019 上,Jon Kalb 发表了有关模板技术的演讲并提到了策略类。来源请参见此处:https://youtu.be/MLV4IVc4SwI?t=1815

有问题的有趣代码片段是:

template<class T, class CheckingPolicy>
struct MyContainer : private CheckingPolicy
{
    ...
}

我经常看到这种类型的设计,我想知道这里的继承是否比组合有任何真正的优势。根据我的个人经验,我听说过很多关于优先选择组合而不是继承范式的说法。所以我编写代码的方式会更像这样:

template<class T, class CheckingPolicy>
struct MyContainer
{
    CheckingPolicy policy;
    ...
}

不会涉及任何虚拟函数。尽管如此,如果您能分享一些它们有何不同的见解,我将不胜感激。我对内存布局的差异及其影响特别感兴趣。如果 CheckingPolicy 没有数据成员,而只有 check 方法或重载的调用运算符,会有什么不同吗?

最佳答案

一个可能的原因:当您继承CheckingPolicy时,您可以从 empty base class optimization 中受益.

如果CheckingPolicyempty (即,除了大小为 0 的位字段之外,它没有非静态数据成员,没有虚函数,没有虚基类,也没有非空基类),它不会对MyContainer 的大小。

相反,当它是MyContainer的数据成员时,即使CheckingPolicy为空,MyContainer的大小也会增加at至少一个字节。至少,因为由于对齐要求,您可能有额外的填充字节。

这就是为什么,例如,在 std::vector 的实现中,您可以从分配器中找到 ihnehritance。例如,libstdc++ 的 implementation :

template<typename _Tp, typename _Alloc>
struct _Vector_base {
    typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
        rebind<_Tp>::other _Tp_alloc_type;

    struct _Vector_impl : public _Tp_alloc_type, public _Vector_impl_data { 
        // ...
    };

    // ...
};

无状态分配器(例如没有非静态数据成员的 CheckingPolicy)不会影响 std::vector 的大小。

在 C++20 中,我们将有 [[no_unique_address]]可能解决此问题:虽然标准布局类型需要空基优化,但 [[no_unique_address]] 只是一个权限,而不是一个要求。 (感谢尼可波拉斯指出了这一点。)

关于基于 C++ 策略的设计 : Inheritance vs composition,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59502951/

相关文章:

c++ - 只是一些简单的错误

inheritance - 在 Objective-C++ 应用程序中接收 C++ 虚拟方法调用的正确方法是什么?

python - 在 Python 中使用 super() 进行 DRY

c++ - ros 到 opencv 图像转换器中的 undefined reference 错误

c++ - Qt 4.8 : connection behavior between two signals and one slot from different threads

c++ - 将枚举打印为字符串

c++ - 为什么我的模板函数不将 'int' 提升为 'T' ,其中 'T' = 'double' ?

c++ - 避免 C++(部分)模板特化中的代码重复

c++ - 如何使派生类在 CRTP 中的基类上模板化

javascript - 为什么 Object#create 必须先于子类的实例化