在 C++ 中重载比较运算符会导致“无效运算符<”
Posted
技术标签:
【中文标题】在 C++ 中重载比较运算符会导致“无效运算符<”【英文标题】:Overloading comparision operator in C++ results in "invalid operator<" 【发布时间】:2011-08-12 18:41:57 【问题描述】:目前正在尝试在 C++ 中对对象向量进行排序,每个对象都包含一个字符串
字符串可以包含字母或数字(由于设计限制,这是必要的,因为比较器可以更改)。
此刻,对象的类被重载了,所以当比较两个对象时,比较它们包含的字符串。这在一定程度上有效——但是,当我使用排序操作(例如 STL 排序)将对象按顺序排列时,它将按顺序对三个字符串进行排序,例如“1”、“4”、“12” “1”、“12”、“4”。 4 大于 12,但因为它从最左边的数字开始比较,所以会发生这种“不正确”的排序。
我最初的反应是改变我重载比较操作的方式。我会首先检查我正在比较的字符串的长度——如果字符串的内容更大或更小,这将是一个迹象。
// overloaded comparision operators
friend bool operator<(const nodeRecord & record1, const nodeRecord & record2)
// we need to deal with strings of different lengths...
if(record1.comparator.length() < record2.comparator.length())
return true;
else
return (record1.comparator < record2.comparator);
此操作在运行时导致“表达式:无效运算符
关于我在哪里犯错的任何想法?看来我应该能够准确地指示操作我希望排序操作如何发生——即使它是无效的,因为我目前正在使用一个向量来包含对象。
nodeRecord对象初始化期间的比较器:
nodeRecord(int fromNode, int toNode, int connectionCost, bool compareByCost = false)
// take the provided stock information and insert it into the object
stringstream fromNodeSS;
fromNodeSS << fromNode;
this->fromNode = fromNodeSS.str();
stringstream toNodeSS;
toNodeSS << toNode;
this->toNode = toNodeSS.str();
this->connectionCost = connectionCost;
// set the comparator to our chosen comparision term
if (!compareByCost)
this->comparator = this->fromNode; // we use from node in this case, since we build the tree outwards
else
stringstream ss;
ss << this->connectionCost;
this->comparator = ss.str(); // we use the connection cost in this case, to allow us to sort new connections
// set this as a non-null (active) record
this->nullRecord = false;
【问题讨论】:
什么是比较器?发布代码。 你能说明比较器的定义吗? @Mike 和 @Mario -- 比较器在 nodeRecord 对象的初始化期间被初始化。你可以在上面看到这个。 【参考方案1】:您的操作员实际上是无效的。
如果您希望运算符<
可用于排序,它必须具有许多数学属性。一个是 AntiSymmetry 属性:
x < y => !(y < x)
让我们定义x = "b"
和y = "aa"
。
x < y
因为"b"
的长度低于"aa"
的长度
y < x
因为"aa"
不如"b"
嗯?
另请注意,如果数字以0
s 为前缀,您的定义会很奇怪。
哦,比较字符串比比较数字要慢。
我的看法?停止使用比较信息更改节点。实际的比较模式与节点本身无关。
那你就写两种比较方法,一种按成本比较,另一种按产地比较。
回到原来的问题,如何编写一个考虑["a", "b", "aa"]
排序的比较器?
您快到了,但“长度”比较不完整。只有在长度不同的情况下,您才需要回退到实际的词法比较,因此您忘记了右侧参数的长度低于左侧参数的情况。
因此正确的形式是,假设有两个字符串:
bool compare(std::string const& lhs, std::string const& rhs)
if (lhs.length() < rhs.length()) return true;
if (rhs.length() < lhs.length()) return false; // don't forget this
return lhs < rhs;
【讨论】:
谢谢!您的解决方案确实帮助我发现并理解了问题所在,并提醒了我另一个我忘记的案例。【参考方案2】:找到下面抛出错误的代码段,然后想想我的重载操作是如何工作的。
template<class _Ty1, class _Ty2> inline
bool _Debug_lt(_Ty1& _Left, _Ty2& _Right,
_Dbfile_t _File, _Dbline_t _Line)
// test if _Left < _Right and operator< is strict weak ordering
if (!(_Left < _Right))
return (false);
else if (_Right < _Left)
_DEBUG_ERROR2("invalid operator<", _File, _Line);
return (true);
工作解决方案是这样的(感谢 Matthieu M. 留下的 cmets 再次修改)
// overloaded comparision operators
friend bool operator<(const nodeRecord & record1, const nodeRecord & record2)
// we need to deal with strings of different lengths...
if(record1.comparator.length() > record2.comparator.length()
&& (record1.comparator.length() !=0 && record2.comparator.length() != 0))
return false;
else if(record1.comparator.length() < record2.comparator.length()
&& (record1.comparator.length() !=0 && record2.comparator.length() != 0))
return true;
else
return (record1.comparator < record2.comparator);
感谢所有帮助过的人!
【讨论】:
【参考方案3】:您为什么不使用单个比较器并让该功能更智能一些?让它检查开头的数字字符,如果是,则执行一对strtol()
或atoi()
并比较结果。
否则根据您的非数字要求比较字符串和字符的长度。
【讨论】:
我希望能够对字符串进行排序,就像我对数字进行排序一样。例如,刺“a”、“aa”和“b”应该按“a”、“b”、“aa”排序。我发布的方法是我所知道的唯一可以让我完成此任务的方法。 不幸的是,这不能解决我的问题。会出现同样的错误=( @BSchlinker:我的回答假设只使用一个operator<
函数,尽管它会比你的复杂得多。以上是关于在 C++ 中重载比较运算符会导致“无效运算符<”的主要内容,如果未能解决你的问题,请参考以下文章
[ C++ ] C++类与对象(中) 类中6个默认成员函数 -- 运算符重载
C++ 继承多态关系中的赋值运算符的重载=operator()