为从 std::vector 派生的类正确重载双等号

Posted

技术标签:

【中文标题】为从 std::vector 派生的类正确重载双等号【英文标题】:Properly overload double equals for a class deriving from std::vector 【发布时间】:2012-06-15 15:03:37 【问题描述】:

我有课

class Item 
    int _one;
    int _two;
    int _three;
    // other stuff
;

class ItemList : public std::vector<Item> 
    // deriving from std vector because the ctor needs to
    // perform some work in discriminating what gets added
    // to the list
;

我已经阅读了许多反对从 std::vector 派生的论点,我想我会没事的,因为这个类不是派生自。我在 python 中公开这个,使用 boost 矢量索引套件,作为 python 列表。因为我需要构造函数在构造过程中从列表中删除某些元素,所以我决定走这条路线,而不是做我在项目其他地方所做的事情:

class AnotherItem 
    // class definition
;
typedef std::vector<AnotherItem> AnotherItemList

然后使用 typedef 使用 boost 向量索引套件公开列表。一切似乎都很好,除了我有这个错误:错误 2 错误 C2678: binary '==' : no operator found which take a left-hand operand of type 'Item' (或没有可接受的转换)

错误不是来自 boost 库,而是来自 std 算法代码。我尝试添加自己的类重载 == 运算符,但这并没有解决问题。它看起来像这样:

class Item 
    // earlier stuff
    bool operator==(Item& rhs) 
        return (_one == rhs._one && _two == rhs._two && _three == rhs._three);
    
    bool operator!=(Item& rhs) 
        return !(*this == rhs);
    
;

这并没有解决问题。我错过了什么?此链接here 表明向量的 == 运算符不是成员函数。我尝试在“全局”级别重载(即不在命名空间内),但这也无济于事。那么,我错过了什么?

谢谢, 安迪

【问题讨论】:

您的第一个问题是来自std::vector... 不要从非设计为继承的类型继承。而是使用组合(即在内部存储 std::vector)。 您应该使 operator==operator!= const 正确。 (即bool operator == (const Item&amp; rhs) const ... 除了通常从矢量问题继承之外,错误是否告诉您 RHS 的预期内容?它是否给出了任何接近的匹配项? 听起来你是从向量派生来对Item 施加一些约束。 Item 是否有任何合理的可能性自行执行这些约束? 我提到我已经看到支持/反对派生自 std::vector 的论点。 (在“for”阵营中提出的一些论点来自 Stack Overflow 的一些线程。)我创建的列表类不应该继承自,所以我不认为 std::vector 中缺少虚拟析构函数 将是一个问题。 @Jerry 我之前没有考虑过你的评论。我必须考虑更多,但我想我可能只能在 ctor 类中添加约束。 【参考方案1】:

== 的正确重载是

class Item

    ...
    bool operator==(const Item& rhs) const
     .... 

    bool operator!=(const Item& rhs) const
     return !(*this==rhs); 
;

另外,请注意,因为std::vector 没有虚拟成员,所以您的派生ItelmList 不能多态地用于std::vector 本身,特别是不要对std::vector* 调用delete。

我必须这样说,否则我和你将注定要被 C++ 社区毁灭,尽管在 30 多年的编程经验中我从来没有从来没有 从来没有 看到了 std::vector* 或 std::string*。 (因此我真的不知道派生 std 类的所有“恐惧”是关于:只需知道你在做什么并让其他人知道)

【讨论】:

您从未见过std::vector*std::string*?显然你没有花任何时间在这里阅读关于 SO 的菜鸟 C++ 问题 ;-) @Rook: :-))) +1 ! -BTW- 新手犯错很正常。什么不是,是防止他们。在我了解 == 和 = 之间的区别后,我停止编写“yoda 比较”(例如 if(0==a)...)。在了解了 virtual 和 not 之间的区别之后,我停止了非虚拟 dtors 的厄运。 看起来我遇到了 const 问题。我已经重新编码了我遵循这种模式和构建的东西。不过,仍在考虑这样做的智慧。尽管我的代码现在可以构建,但考虑到从 std::vector 派生的非常严肃的考虑,我不确定它是否会保持这种状态。这个类永远不应该派生自。再一次,有人告诉我,我也永远不需要超过 640k 的 RAM。

以上是关于为从 std::vector 派生的类正确重载双等号的主要内容,如果未能解决你的问题,请参考以下文章

C++:当包含从类模板派生的类的标头时,编译器警告 C4505

正确分配 std::vector

c++基类对象的std::vector----派生类的运行方法

向量和派生向量类之间的区别

是否可以重载模板函数以与std :: vector的元素一起使用?

将使用 PIMPL 习语的类存储在 std::vector 中