2009-11-07 67 views
10

在我的作業中,我必須設計一個類Message;在其他屬性中,它具有屬性「優先級」(主要目標是實現優先級隊列)。在同一類中重載operator <和operator>

在容器中,我必須檢查一個對象是否大於其他對象,我重載了操作符'>'。現在,我有一個關於它的一些一般性的問題...

問題一:

如果我重載運算符「>」,我應該重載運算符「<」的參數(const的消息&,常量消息& )?

我的看法是,超載都>和<,並使用它的代碼將產生錯誤:

if(message1 > message2) 
    { ... } 

(執行以下代碼調用運營商>爲MESSAGE1對象,或運營商< MESSAGE2對象?)

但是,如果我用運營商這樣的內容:

if(message1 < message2) 
    { ... } 

操作>聲明爲友元函數:

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

是否需要被聲明爲成員函數?

謝謝。

回答

21

If I overload operator '>', should I overload operator '<' for argumenst (const Message&, const Message&)?

是的。實際上,在大多數代碼中,約定使用<而不是>(不要問我爲什麼,可能是歷史)。但更一般地說,總是使整套相關操作符過載;在你的情況下,這也可能是==,!=,<=>=

(Does the following code calls operator > for message1 object, or operator < message2 object?)

它總是調用它在代碼中找到的內容。對於C++編譯器,><之間絕對沒有關係。對我們來說,它們看起來很相似,但編譯器會看到兩個完全不同的,無關的符號。所以沒有歧義:編譯器調用它所看到的。

Does it need to be declared as member function?

不。實際上,最好不要聲明爲成員函數。將其聲明爲成員函數意味着第一個參數(即表達式的左側)必須是一個Message對象,而不是可以隱式轉換爲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) … 

雖然存在從01的隱式轉換到RealFraction(使用第一個構造函數)。

另一方面,如果您使用了非成員函數來實現該運算符,則兩種比較都可以工作,因爲C++會知道在第一個參數上調用隱式構造函數。

+0

謝謝,我在某處讀到,如果我重載一個關係操作,那麼重載所有關係操作似乎是合理的。 – 2009-11-07 15:17:49

+0

謝謝你的朋友/會員回答。我明白你的意思了 :)。 – 2009-11-07 15:19:55

+3

這個答案也應該指出,大多數關係運算符可以用少數運算符來描述,通常是'<'和'=='。例如,'operator> ='可以寫成:'bool operator> =(const T&l,const T&r){return!(l greyfade 2013-09-09 22:17:07

8

是的,你應該......但你可以(而且按理說應該)實現三個<><=>=在另外一個方面。這確保了他們的行爲一致。通常,<是其他實施方式中的一個,因爲它是set s和map s中使用的默認運算符。

E.g.如果您實施了<,則可以像這樣定義>,<=>=

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 < a)更嚴格的關係。但是,這樣做確實會給班級的客戶帶來更多的複雜性。

在某些情況下是可以接受的,以有<><=>=但不==!=

+1

是的,是的,是的!我忘記提及這一點,但這很重要。你應該也可以說你的乾淨的代碼將和手動和獨立地編碼每個比較一樣高效。這是非常重要的,因爲這意味着任何試圖放棄這種建議而傾向於性能的嘗試都是不成熟的優化。 – 2009-11-07 15:42:29

+2

這樣的人也可以使用快捷方式,比如''中的'class Message:boost :: less_than_comparable '和'rel_ops'(後者的味道有些可疑,因爲它們可以被使用宣言)。使用'operator <'就足夠了,其他的都可以用它來實現。 – UncleBens 2009-11-07 15:45:53

+0

OTOH,試圖使用'rel_ops' _can_會非常痛苦。通常你必須將它們導入到另一個命名空間,並且它們往往過於貪婪。如果你的類在全局名字空間中,你最終可以用'rel_ops'來比較各種不合適的類型。 – 2009-11-07 15:53:30

4

如果賦值沒有明確要求使用運算符重載,也可以考慮使用函數對象。原因在於可能有多種方法比較兩個消息的「小於」(例如比較按照字典順序排列的內容,發佈時間等),因此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 
     //... 
    } 
};