扩展std::vector时,该选择组合还是继承?
方案选择建议:组合优先,搭配适配层兼顾易用性
你的核心需求是必须保证所有元素都经过解析流程,无法直接篡改或添加未解析内容,基于这个优先级最高的要求,我们来分析两种方案的适配性,并给出更优实现:
为何不推荐继承std::vector
继承方案的隐患远大于便利:
- 你需要逐一删除或重写std::vector所有能直接修改内部的接口,包括10+个构造函数、
emplace/insert/push_back等修改方法,甚至非const的operator[],工作量极大。 - 若后续C++标准库给vector新增修改类方法,你的类会直接出现漏洞——用户可以通过新方法绕过解析规则,完全违背你的设计初衷。
- 语义上,你的
query2并非"vector的扩展",而是"基于解析规则的路径容器",继承会模糊这个核心定位。
组合方案的优化实现
组合是更贴合需求的选择,它能完全控制对外接口,同时通过适配层复用vector的特性,避免重复造轮子:
示例实现
#include <vector> #include <string_view> #include <algorithm> struct Query { // 仅允许从字符串解析构造 explicit Query(std::string_view path) { parse(path); } // 赋值操作也必须走解析流程 Query& operator=(std::string_view path) { str_.clear(); parse(path); return *this; } // 暴露只读迭代器,复用vector的迭代器逻辑 auto begin() const noexcept { return str_.begin(); } auto end() const noexcept { return str_.end(); } auto cbegin() const noexcept { return str_.cbegin(); } auto cend() const noexcept { return str_.cend(); } // 只读元素访问 const std::string_view& operator[](size_t idx) const noexcept { return str_[idx]; } const std::string_view& at(size_t idx) const { return str_.at(idx); } // 常用容器属性 size_t size() const noexcept { return str_.size(); } bool empty() const noexcept { return str_.empty(); } // 安全转换为const vector引用,兼容接受vector的函数 const std::vector<std::string_view>& as_vector() const noexcept { return str_; } private: std::vector<std::string_view> str_; // 核心解析逻辑:按'/'分割路径 void parse(std::string_view path) { // 跳过开头的'/' if (!path.empty() && path.front() == '/') { path = path.substr(1); } size_t pos = 0; while (pos < path.size()) { const size_t next_slash = path.find('/', pos); if (next_slash == std::string_view::npos) { str_.push_back(path.substr(pos)); break; } str_.push_back(path.substr(pos, next_slash - pos)); pos = next_slash + 1; } } };
组合方案的优势
- 完全可控:所有外部修改都必须经过解析函数,彻底杜绝绕过规则的可能,哪怕std::vector后续新增方法也不会影响。
- 低重复开发:直接复用vector的迭代器、元素访问逻辑,仅需实现解析核心和必要的适配接口。
- 语义清晰:类的定位明确为"路径解析容器",其他开发者能快速理解其用途和限制。
- 兼容现有代码:通过
as_vector()方法可以安全地将内部数据传递给接受const vector的函数,同时保证外部无法修改。
总结
你的场景下组合方案是最优选择,它完美契合"数据必须经过解析、不可篡改"的核心需求,同时通过适配层兼顾了std::vector的易用性。继承方案因存在不可控的安全隐患和高昂的维护成本,并不适合你的需求。
内容的提问来源于stack exchange,提问作者glades
相关产品推荐
相关产品推荐

