【发布时间】:2021-12-02 01:45:55
【问题描述】:
我目前正在开发一个类似于std::vector 的自定义 C++ 容器库,但我也希望包含std::span 的功能。特别是,我希望能够编写能够接收std::span-like 参数,也可以使用 std::vector-like 参数。
我可以做的是构造一个类,比如my_vector,以及另一个可以从类my_vector 转换的类my_span。这就是 STL 所做的,我知道模仿标准库通常是个好主意。但我有这样的想法,my_span 基本上是一个不拥有内存的my_vector,因此可以使用继承来实现这两个类。这是它在代码中的样子。
class my_vector;
class my_span {
private:
/* span sees [data_ + start_, data_ + stop_) */
T* data_;
size_t start_;
size_t stop_;
friend class my_vector;
public:
/* Member functions operating on non-owning memory */
};
class my_vector : public my_span {
private:
size_t cap_;
public:
/* Member functions like resize, push_back, etc. */
};
现在我的同事基于以下原因拒绝了这个想法。公平地说,我对他的反对意见的表述可能并不忠实。
- 在实际容器之前定义跨度是违反直觉的。
- 在扩展派生类时使用继承,但类
my_vector的条件是其成员start_将始终为0。 (有一些原因迫使指针data_始终指向分配内存的开头。这就是为什么我不能只使用指针和跨度的长度。)
另一方面,我认为这种设计有以下好处。
- 如果你仔细想想,
my_vector仍然“是”my_span。它只是一个拥有内存并且可以更改大小的my_span。 - 每个对非拥有内存进行操作的成员函数只能声明和实现一次;
my_vector类自动继承它。 - 要将
my_vector用作my_span,您无需创建新的my_span实例。向上转换比构造函数更自然。
我还没有看到遵循这种模式的设计,所以我想获得更多关于这是否是一个好的设计的意见。
【问题讨论】:
-
Stack Overflow 是一个获取意见的好地方。它更像是一个具体的答案。
-
我不喜欢基类是派生类的
friend。随着更多派生类的添加,它不能很好地扩展。protected通常是更好的解决方案。 -
我个人不会继承,而是为
my_vector提供隐式转换运算符到my_span。是的,您正在创建一个新对象,但如果my_span只是成为一个指针和一个大小,那将非常便宜。您还可以将 span 与 vector 分离,正如您所指出的,您已经必须向 span 添加一个成员,而 span 工作不需要该成员。
标签: c++ stl containers library-design