代码之家  ›  专栏  ›  技术社区  ›  Nemanja Boric

重载同一类中的运算符<和运算符>。

  •  12
  • Nemanja Boric  · 技术社区  · 15 年前

    在我的家庭作业中,我必须设计一个类消息;在其他属性中,它具有属性“优先级”(主要目标是实现优先级队列)。

    和容器中一样,我必须检查一个对象是否大于另一个对象,我已经重载了运算符“>”。现在,我有几个关于它的一般性问题…

    问题一:

    如果重载运算符“>”,是否应重载参数的运算符“<”(const message&,const message&)?

    我的观点是,重载>和<并在代码中使用它将产生错误:

    if(message1 > message2)
       { ... }
    

    (以下代码是为message1对象调用operator>还是为operator<message2对象调用operator?)

    但是,如果我使用这样的操作符会怎么样:

    if(message1 < message2)
       { ... }
    

    ?

    operator>声明为friend函数:

    friend bool operator>(const Message& m1, const Message& m2)
    

    它是否需要声明为成员函数?

    谢谢您。

    3 回复  |  直到 10 年前
        1
  •  24
  •   Konrad Rudolph    15 年前

    如果我重载运算符“>”,是否应重载参数的运算符“<”(const message&,const message&)?

    对。事实上,在大多数代码中,它的约定更倾向于使用 < 结束 > (不要问我为什么,可能是历史性的)。但更一般地说,总是重载整个相关的运算符集;在您的情况下,这也可能是 == , != ,请 <= >= .

    (以下代码是为message1对象调用operator>还是为operator<message2对象调用operator?)

    它总是调用代码中找到的内容。对于C++编译器,它们之间绝对没有连接。 > < . 对于我们来说,它们看起来很相似,但是编译器看到了两个完全不同的、不相关的符号。所以没有歧义:编译器调用它所看到的。

    它是否需要声明为成员函数?

    不。事实上,它最好不要声明为成员函数。将其声明为成员函数意味着第一个参数(即表达式的左侧)必须是 Message 对象,而不是隐式转换为 消息 .

    要理解这一点,请考虑以下情况:

    struct RealFraction {
        RealFraction(int x) { this.num = x; this.den = 1; }
        RealFraction(int num, int den) { normalize(num, den); }
        // Rest of code omitted.
    
        bool operator <(RealFraction const& rhs) {
            return num * rhs.den < den * rhs.num;
        }
    };
    

    现在您可以编写以下比较:

    int x = 1;
    RealFraction y = 2;
    if (y < x) …
    

    但是你 不能 写下以下内容:

    if (x < y) …
    

    尽管存在隐式转换 int RealFraction (使用第一个构造函数)。

    另一方面,如果您使用非成员函数来实现运算符,则两个比较都可以工作,因为C++将知道在第一个参数上调用隐式构造函数。

        2
  •  11
  •   Uyghur Lives Matter    10 年前

    是的,你应该…但是您可以(并且可以说应该)实现 < , > , <= , >= 就另一个而言。这确保了他们的行为始终如一。通常 < 是另一个实现的,因为它是中使用的默认运算符 set S和 map S.

    例如,如果实施 < ,你可以定义 > , <= >= 这样地。

    inline bool operator>(const Message& lhs, const Message& rhs)
    {
        return rhs < lhs;
    }
    
    inline bool operator<=(const Message& lhs, const Message& rhs)
    {
        return !(rhs < lhs);
    }
    
    inline bool operator>=(const Message& lhs, const Message& rhs)
    {
        return !(lhs < rhs);
    }
    

    == != 通常是单独实现的。有时类实现 = 这样的话 a == b 当且仅当 !(a < b) && !(b < a) 但有时 = 是作为比 !(A<B)&!(b & lt;a) . 不过,这样做确实会使类的客户机更加复杂。

    在某些情况下,可以接受 < , > , <= >= 但不是 = != .

        3
  •  5
  •   UncleBens    15 年前

    如果分配没有显式地要求使用运算符重载,您也可以考虑使用函数对象。原因是,可能有不止一种方法可以比较“小于”的两条消息(例如,按字典法比较内容、发布时间等),因此 operator< 直觉上不清楚。

    std::priority_queue 要使用的函数对象被指定为第三个模板参数(不幸的是,您还需要指定第二个底层容器类型):

    #include <queue>
    #include <string>
    #include <functional>
    #include <vector>
    
    class Message
    {
        int priority;
        std::string contents;
        //...
    public:
        Message(int priority, const std::string msg):
            priority(priority),
            contents(msg)
        {}
        int get_priority() const { return priority; }
        //...
    };
    
    struct ComparePriority:
        std::binary_function<Message, Message, bool> //this is just to be nice
    {
        bool operator()(const Message& a, const Message& b) const
        {
            return a.get_priority() < b.get_priority();
        }
    };
    
    int main()
    {
        typedef std::priority_queue<Message, std::vector<Message>, ComparePriority> MessageQueue;
        MessageQueue my_messages;
        my_messages.push(Message(10, "Come at once"));
    }
    

    在实现自己的优先级队列时,可以按以下方式进行:

    class MessageQueue
    {
        std::vector<Message> messages;
        ComparePriority compare;
        //...
        void push(const Message& msg)
        {
            //...
            if (compare(msg, messages[x])) //msg has lower priority
            //...
        }
    };