如何在C++基类中新增缓冲区且不浪费额外空间?
问题背景
之前的代码实现
最初仅支持ColorBook(RedBook/BlueBook/YellowBook),所有ColorBook共用基类Book中的color_book_buffer:
struct RedBook : Book {...} struct BlueBook : Book {...} struct YellowBook : Book {...} struct Book { virtual ~Book() = default; // ... static constexpr int COLOR_BOOK_SIZE = 100; char color_book_buffer[COLOR_BOOK_SIZE] = {0}; // 仅由ColorBook使用 };
需求变更后的现状
新增支持NoColorBook(GrayBook/DarkBook),这类Book需要使用单独的no_color_book_buffer,但直接在Book中同时加入两个缓冲区会造成空间浪费:
struct GrayBook : Book // 新增 {} struct DarkBook : Book {} struct Book // 更新后的Book结构 { virtual ~Book() = default; // ... static constexpr int COLOR_BOOK_SIZE = 100; char color_book_buffer[COLOR_BOOK_SIZE] = {0}; // 仅由RedBook/BlueBook/YellowBook使用 // ... static constexpr int NOCOLOR_BOOK_SIZE = 200; char no_color_book_buffer[NOCOLOR_BOOK_SIZE] = {0}; // 仅由GrayBook/DarkBook使用 };
现有方案的不足
已有的三个方案均不符合预期:
- 方案1:将缓冲区移至子类,导致每个子类重复定义缓冲区代码,冗余度高
- 方案2:新增ColorBook和NonColorBook两层基类,拆分了原有的Book体系结构
- 方案3:使用
std::max取两种缓冲区的最大尺寸作为统一缓冲区,仍存在空间浪费(NoColorBook无需占用ColorBook的大缓冲区)
更优解决方案:Mixin混入类 + 虚拟基类
通过Mixin类为不同类型的Book注入对应的缓冲区,同时保持Book作为统一的基类,既避免空间浪费,又不重复代码,也不拆分原有体系。
实现代码
// 统一的Book基类,仅包含所有Book共有的逻辑 struct Book { virtual ~Book() = default; // 这里放所有Book都需要的公共方法/成员 }; // ColorBook的Mixin类,提供color_book_buffer template <typename Derived> struct ColorBookMixin : virtual Book { static constexpr int COLOR_BOOK_SIZE = 100; char color_book_buffer[COLOR_BOOK_SIZE] = {0}; }; // NoColorBook的Mixin类,提供no_color_book_buffer template <typename Derived> struct NoColorBookMixin : virtual Book { static constexpr int NOCOLOR_BOOK_SIZE = 200; char no_color_book_buffer[NOCOLOR_BOOK_SIZE] = {0}; }; // 子类通过继承对应的Mixin来获得缓冲区 struct RedBook : ColorBookMixin<RedBook> {}; struct BlueBook : ColorBookMixin<BlueBook> {}; struct YellowBook : ColorBookMixin<YellowBook> {}; struct GrayBook : NoColorBookMixin<GrayBook> {}; struct DarkBook : NoColorBookMixin<DarkBook> {};
方案优势
- 无空间浪费:每个子类仅包含自己需要的缓冲区,不会携带无用的内存空间
- 无代码重复:缓冲区的定义集中在Mixin类中,子类只需继承即可,避免重复代码
- 保持体系统一:所有子类最终都继承自Book基类,原有多态逻辑不受影响(比如可以用
Book*指向任意子类对象) - 扩展性强:后续新增其他类型的Book时,只需新增对应的Mixin类即可,无需修改原有代码
可选方案:CRTP实现类型特化
如果需要更灵活的类型区分,也可以用CRTP结合类型 traits 来实现:
#include <type_traits> struct Book { virtual ~Book() = default; }; // 类型 trait 标记ColorBook类型 template <typename T> struct is_color_book : std::false_type {}; template <> struct is_color_book<RedBook> : std::true_type {}; template <> struct is_color_book<BlueBook> : std::true_type {}; template <> struct is_color_book<YellowBook> : std::true_type {}; // CRTP基类,根据子类类型注入对应缓冲区 template <typename Derived> struct BookImpl : Book { static constexpr bool is_color = is_color_book<Derived>::value; static constexpr int BUFFER_SIZE = is_color ? 100 : 200; char buffer[BUFFER_SIZE] = {0}; // 类型安全的缓冲区访问方法 char* get_buffer() { return buffer; } }; struct RedBook : BookImpl<RedBook> {}; struct BlueBook : BookImpl<BlueBook> {}; struct YellowBook : BookImpl<YellowBook> {}; struct GrayBook : BookImpl<GrayBook> {}; struct DarkBook : BookImpl<DarkBook> {};
这个方案用统一的buffer成员,根据子类类型自动确定尺寸,同样避免空间浪费,且代码更紧凑。
内容的提问来源于stack exchange,提问作者q0987
相关产品推荐
相关产品推荐

