C++ 重构从std::container继承的类

C++ 重构从std::container继承的类,c++,inheritance,C++,Inheritance,我有一个包含5个类的中间代码块,它们都是从标准容器继承的。例如: class Step : public std::vector<unsigned int> { public: friend std::ostream& operator<<(std::ostream& outStream, const Step& step); Step& operator =(const Step& rhv); static

我有一个包含5个类的中间代码块,它们都是从标准容器继承的。例如:

class Step : public std::vector<unsigned int>
{
public:
    friend std::ostream& operator<<(std::ostream& outStream, const Step& step);
    Step& operator =(const Step& rhv);
    static Step fromString(const std::string &input);
    std::string name;
};
类步骤:公共std::vector { 公众: friend std::ostream&operator
typedef std::vector data\u t;
数据;
引入typedef简化了方法的所有签名,并降低了vector类型更改的风险

我知道从标准容器继承是个坏主意

这在许多情况下都是有意义的。如果您认为总是一个坏主意,那么您就错了。如果从标准容器继承使代码变得简短易读,那么从STL容器继承是一个好主意。在我的看来,您的第一个类(继承了std::vector)比第二个好

问题:您建议如何通过小改动来修改代码

如果你想浪费时间只是为了好玩

首先,您可以删除“公共好友”功能,这没有任何意义

然后声明几个typedef

typedef std::string Name;

class Step{
protected:
    typedef std::vector<int> Data;
    Data data;
public:
    typedef Data::const_iterator ConstIterator;
    Step& operator=(const Step& other);
    static Step fromString(const std::string &input);
    Name name;
    ConstIterator begin() const;
    ConstIterator end() const;
    size_t size() const;
};
typedef std::字符串名称;
类步{
受保护的:
typedef std::矢量数据;
数据;
公众:
typedef数据::常量迭代器;
步骤和运算符=(常量步骤和其他);
静态步骤fromString(const std::string和input);
姓名;
construtator begin()常量;
construtator end()常量;
大小\u t大小()常量;
};

并在与Step交互的所有代码中使用这些TypeDefed类型。这样,您以后就可以更改内部类型(例如,用std::deque替换std::vector,或实现自定义迭代器类),而无需修改整个项目。

最好的解决方案是首先将您的功能重构为自由函数:

namespace Step2 {
  std::vector<unsigned int> fromString(const std::string &input);
}
命名空间步骤2{
std::vector fromString(const std::string和input);
}
然后为旧API提供独立的标头:

  DEPRECATED class Step : public std::vector<unsigned int>
  {
    public:
    inline static Step fromString(std::string const& input);
    {
      return Step(Step2::fromString(input));
    }
  };
不推荐的类步骤:public std::vector
{
公众:
内联静态步骤fromString(std::string const&input);
{
返回步骤(步骤2::fromString(输入));
}
};

一个可能的解决方案:使继承私有化(或受保护,如果有意义的话),并使用相关成员:

class Step : private std::vector<int>
{
    typedef std::vector<int> base_;

public:
    using base_::operator[];
    using base_::size;
    ...

};
类步骤:私有std::vector
{
typedef std::向量基;
公众:
使用基本运算符[];
使用基本尺寸;
...
};

如果继承确实使代码变得更简单,那么您可能会喜欢这个解决方案。从容器继承的真正问题是,一旦您向
步骤
类添加成员,到
向量
的转换可能会给您带来麻烦:析构函数会发生变化,您知道,它一开始就不是虚拟的。私有继承因此解决这个问题。

我不理解这个问题。请澄清…无关的建议:由于您可以通过迭代器从类外访问数据,您不需要友谊(应该避免友谊)。相关建议:这些是您的类中使用的唯一操作吗?(只读开始/结束/大小?)@DavidRodríguez dribeas:我不知道客户端使用了哪些操作。唯一已知的事实是类本身应该被视为
std::vector
。因此标准向量的所有操作都应该在类中可用。在不更改类定义的情况下,不能删除继承。你必须这样或那样做,添加系统使用的方法。如果是我,我会一次删除一个类的继承,重新生成项目,并添加编译器/链接器抱怨的方法。根据您在注释中提供的信息,最明智的做法是实际设计类应该做什么,并且应该像向量一样运行这是一个选项。如果没有访问用户代码的权限,除了通过转发重新实现整个矢量接口之外,您无法进行非破坏性的更改,这实际上并不比您所拥有的好多少。如果您要进行破坏性更改,那么请设计并提供一个用户应该能够使用
St的合理界面ep
并发布带有巨大警告的新库。那么不支持的操作是什么意思?你说的“不支持”是什么意思?在
Step
类中有一些变量和方法,它们不在
vector
@sorush-r中。如果您需要这些变量和方法,请使用它们!听起来是最好的解决方案。谢谢。据我所知,标准容器没有虚拟析构函数,所以这不是原因吗在某些情况下未定义的行为?@sorush-r:我同意SigTerm的观点,这并不意味着在最简单的情况下不能继承标准容器类(我知道在某些情况下它可以简化问题)。当您的团队中有人向类中添加成员时,真正的问题就会出现。因此,在源代码共享的情况下,编码约定应该会阻止人们继承容器。@sorush-r:“没有虚拟析构函数”不是问题,只要您不使用指向基类的指针删除对象(例如,
std:;vector
或其他)。在大多数情况下,这(使用指向基的指针删除)是不必要的。您可以轻松地使用类(从容器派生)作为非指针成员变量。我认为将虚拟析构函数添加到派生类中应该不会有太大问题。当然,这不会阻止有人下定决心将您的派生类转换回
std::vector
,但我不确定为什么有人首先要这样做
  DEPRECATED class Step : public std::vector<unsigned int>
  {
    public:
    inline static Step fromString(std::string const& input);
    {
      return Step(Step2::fromString(input));
    }
  };
class Step : private std::vector<int>
{
    typedef std::vector<int> base_;

public:
    using base_::operator[];
    using base_::size;
    ...

};