我有一个名为IndexSet的对象,当前定义为std :: vector,我想将其定义为单独的类型。
我希望能够与它进行交互,就好像它是一个向量,但我也想要类型保护,这样我就不会意外地使用"正常"当我想使用IndexSet时向量。
我已经能够提出三种选择,如何做到这一点,没有一个让我高兴。我希望有四分之一我不在。
选项#1:typdef
typdef vector<int> IndexSet
这允许我完全像我的向量一样使用IndexSet,但它给了我零类型保护。我能够将一个向量传递给一个期望一个没有投诉的IndexSet的函数。
选项#2:公共包装类
class IndexSet
{
public:
vector<int> indexes;
};
这会给我类型保护,但它要求我使用与它交互的间接级别。而不是说 set.push_back(1); 我不得不说 set.indexes.push_back(1);
选项#3:私有包装类
class IndexSet
{
public:
push_back....
operator[]...
etc...
private:
vector<int> indexes
};
这将给我两种类型保护,并允许我直接与IndexSet交互,就好像它是一个向量,但只有我首先为std :: vector的每一个方法创建包装器方法,我想用我的索引集。
当然,我真正想做的就是创建一个继承自vector但又没有自己实现的新类,但我知道标准库容器不喜欢继承自
我还有其他选择吗?
答案 0 :(得分:3)
IndexSet
和向量之间是否存在某些功能不同?这些物体的使用方式有什么不同吗?如果答案是否定的,那你为什么要这样做?
只有在向需要std::vector<int>
的函数提供IndexSet
时才会出现本质上错误的内容,因此typedef不够用。这表明IndexSet
不满足std::vector<int>
的is-a关系。这反过来意味着即使你可以公开继承,也不应该这样做。
如果关系是通过而不是is-a实现的,则建议使用包含或私有(可能是受保护的)继承。这比容器类的公共继承更安全,因为使用您的类的程序员必须不遗余力地获取基类指针。 (这样做的方法是使用C风格的转换。即使继承不公开,C风格的转换也可以将派生类型转换为父类。)
在这种情况下使用私有继承代替包含 的优点是,您可以通过using
语句轻松地将选定的继承成员函数从private提升为protected。如果使用包含,则必须编写一堆包装函数。
class IndexSet : private std::vector<int> {
public:
// Bunch of constructors, elided.
using std::vector<int>::push_back;
using std::vector<int>::operator[];
using std::vector<int>::cherry_picking_of_only_the_stuff_you_want;
};
<强>更新强>
有一些非成员函数与std::vector
相关联,特别是比较运算符和std::swap
。为IndexSet
制作可比较的版本将需要包装器功能,但是没有那么多(六个比较运算符加std::swap
),如果该功能对此类有意义,则只需要这些功能。
答案 1 :(得分:1)
让我们面对现实,一种解决方案具有所有优势,只有一个缺点。
如果你继承std :: vector,你只需要确保不要将指针混合到std :: vector和你的类,所以没有人会删除指向std :: vector的指针,当它实际上是你的子类。
这是否可行取决于您的项目。如果这是一个将被很多人使用的对象,在公共库,OSS项目等中,您可能更安全地包装它,否则只是子类std::vector
。你没事。
不要忘记在课程界面添加评论来解释危险。并且您可以禁用强制转换操作符以获得额外的安全性(使您的ctor明确,...)。
答案 2 :(得分:0)
这听起来像...... BOOST_STRONG_TYPEDEF
的工作。 http://www.boost.org/doc/libs/1_54_0/boost/serialization/strong_typedef.hpp
BOOST_STRONG_TYPEDEF(std::vector<int>, IndexSet)