C++基于策略的设计:继承与组合
C++ policy based design: Inheritance vs composition
在2019 C++会议上,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
继承时,你可以从空基类优化中受益。
如果CheckingPolicy
为空(即它没有非静态数据成员,除了大小为0
的位字段、没有虚函数、没有虚拟基类和没有非空基类(,它不会对MyContainer
的大小做出贡献。
相反,当它是MyContainer
的数据成员时,即使CheckingPolicy
为空,MyContainer
的大小也会增加至少一个字节。至少,因为由于对齐要求,您可能会有额外的填充字节。
这就是为什么,例如,在实现std::vector
时,您可以从分配器中找到属性。例如,libstdc++ 的实现:
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]]
只是权限,而不是要求。(感谢Nicol Bolas指出这一点。
- 混合组合和继承的C++问题
- C++基于策略的设计:继承与组合
- 工厂方法模式使用继承而抽象工厂模式使用组合如何
- vector_base继承与组合
- 如何在 c++ 中将多重继承与组合一起使用?
- 是否可以使用 Gtk::D rawingArea (GTKmm) 作为组合而不是继承?
- C++:树根应该使用继承而不是组合吗?
- 必要时违反组合而不是继承可以吗?
- 避免使用组合进行额外的堆分配(过度继承)
- 为什么我在使用组合而不是继承时得到 C4624(无法访问基类析构函数)
- 编译器如何在继承C++中进行组合
- 类继承/组合设计
- Qt和C++:双重继承与组合
- 使用组合而不是继承的方法转发(使用C++特性)
- 将继承更改为组合
- C++中组合关系的继承
- 为什么与组合相比,私有继承会增加有人破坏我的代码的概率
- 两个接口,多个继承组合成一个容器
- 运算符<<和继承/组合
- c++中创建多继承组合类的设计指南