如何使std :: vector类型安全

时间:2014-04-11 15:18:30

标签: c++ stl

我有一个名为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但又没有自己实现的新类,但我知道标准库容器不喜欢继承自

我还有其他选择吗?

3 个答案:

答案 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)