【问题标题】:Problem overloading the < operator in C++在 C++ 中重载 < 运算符的问题
【发布时间】:2009-10-12 01:52:07
【问题描述】:

我有一个 Student 对象向量,我想使用 #include &lt;algorithm&gt;sort(list.begin(), list.end()); 对其进行排序

为了做到这一点,我知道我需要重载“

这是我最近的尝试:

在 Student.h...

...
using namespace std;
class Student
{
    friend bool operator <(const Student& first, const Student& second);
    public:
    ...
    private:
    ...
};

在 Student.cpp...

...
#include "Student.h"
using namespace std;
...
bool operator <(const Student& first, const Student& second)
{
    return first.Name() < second.Name();
}

其中“Name()”是一个返回字符串的常量函数。

程序编译并运行,但在排序过程中从未调用过我的运算符函数,当我尝试比较两个学生对象(如 s1 &lt; s2)时,我收到“错误:未找到重载运算符”

如何正确重载此运算符,以便我的排序按预期工作?

【问题讨论】:

    标签: c++ operator-overloading


    【解决方案1】:

    您没有说您使用的是哪个编译器,但我怀疑您使用的是一个相当新的编译器,它实现了“朋友不是声明”规则。类中的friend语句不用作函数声明;包含 Student.h 的其他模块看不到该函数的任何声明。它仅在 Student.cpp 文件中可见。 (老的编译器没有这个规则,把友元声明当作函数声明。)

    该函数不需要是朋友,因为它不使用 Student 类的任何私有成员(我假设 Name() 是公共的)。将函数声明移到类外,将“friend”替换为“extern”,它应该可以工作。

    可以使操作员成为成员函数,正如上面的一些海报所建议的那样,但这不是必需的。使比较运算符成为成员函数通常是不受欢迎的,因为这意味着两个参数没有得到对称处理(一个是不可见的“this”参数,另一个是普通函数参数),这在某些情况下会导致令人惊讶的结果(例如,可以对参数应用不同的类型转换)。

    【讨论】:

    • 函数声明是否需要标记extern?我只是用头文件中声明的变量来完成。
    • 很难为这个问题决定一个单一的答案。我最初的尝试都是在课堂上定义的,在阅读有人声称除非你这样做,否则“排序”不会生效后,我只是出于绝望才尝试了“朋友”版本。原来我其实也遇到了指针相关的问题。
    • 确实,这不是必需的;默认情况下,类外的函数具有外部链接。我习惯将其放入以向读者表明该函数是在另一个源文件中定义的(而不是在同一文件中的其他位置定义的函数的前向声明)。
    • @Ross - 我理解这种皱眉,但我个人对编写标准的人皱眉。逻辑对称的方法是拥有一个静态成员函数,但显然这是不允许的。无论如何,我的习惯是因为朋友方法的问题而形成的——这些问题现在可能已经消失了,但我现在的习惯并没有给我带来任何问题。 IMO,“如果它没有坏就不要修复它”也适用于习惯。
    【解决方案2】:

    我不会在这里使用朋友,而且我不确定它是否有效。我会使用的是...

    class Student
    {
      public:
        bool operator< (const Student& second) const;
    };
    
    bool Student::operator< (const Student& second) const
    {
      return (Name() < second.Name());
    }
    

    注意后面的const,表示在operator

    编辑我无法删除此答案,因为它已被接受,但如果可以的话,我会这样做。我也无法用正确的替换它。请参阅下面的 Drew Dormanns 评论和Ross Smiths answer

    【讨论】:

    • 我想我最终决定将其作为我将选择的答案,因为它最直接地让我发现了我的指针所遇到的更大问题。
    • 这种方法经常被避免,因为如果类型可以转换为Student,代码将转换右侧类型而不是左侧类型。友元函数对双方都表现一致。
    【解决方案3】:

    顺便说一句,对于这么简单的函数,我个人会这样做,除非样式指南禁止在类定义中定义函数:

    class Student
    {
        friend bool operator <(const Student& first, const Student& second)
        {
            return first.Name() < second.Name();
        }
        ...
    };
    

    这种形式的“朋友”声明允许您在类的主体内定义一个非成员operator&lt;。它仍然是朋友,所以如果需要,Name() 可以是私人的。

    【讨论】:

      【解决方案4】:

      嗯,你可以作为内部操作员来做:

      class Student
      {
          public:
          bool operator <(const Student& second) const;
          ...
          private:
          ...
      };
      

      通过将“this”与第二个进行比较的实现。我心中的问题是:'Name' 方法是否具有 const 风格?因为如果没有,那么你就不能编写使用它的 const 方法。

      【讨论】:

      • 似乎很可能 - 朋友版本中的“first”和“second”参数都是 const。
      猜你喜欢
      • 2014-04-14
      • 1970-01-01
      • 1970-01-01
      • 2011-01-27
      • 1970-01-01
      • 1970-01-01
      • 2010-11-05
      • 2011-03-22
      • 2018-05-01
      相关资源
      最近更新 更多