C++基礎教程面向物件(學習筆記(24))
過載比較運算子
過載比較運算子相對簡單,因為它們遵循我們在過載其他運算子時看到的相同模式。
因為比較運算子都是不修改左運算元的二元運算子,所以我們將使過載的比較運算子宣告為友元函式。
這是一個帶有過載運算子==和operator!=的Car類的示例。
#include <iostream> #include <string> class Car { private: std::string m_make; std::string m_model; public: Car(std::string make, std::string model) : m_make(make), m_model(model) { } friend bool operator== (const Car &c1, const Car &c2); friend bool operator!= (const Car &c1, const Car &c2); }; bool operator== (const Car &c1, const Car &c2) { return (c1.m_make== c2.m_make && c1.m_model== c2.m_model); } bool operator!= (const Car &c1, const Car &c2) { return !(c1== c2); } int main() { Car corolla ("Toyota", "Corolla"); Car camry ("Toyota", "Camry"); if (corolla == camry) std::cout << "a Corolla and Camry are the same.\n"; if (corolla != camry ) std::cout << "a Corolla and Camry are not the same.\n"; return 0; }
這裡的程式碼應該是很直接的。因為operator!=的結果與operator 相反,我們根據operator定義operator!=,這有助於使事情更簡單,更無錯誤,並減少我們編寫的程式碼量。
operator<和operator>怎麼樣?汽車比另一輛汽車更大或更小的意義是什麼?我們通常不會這樣考慮汽車。由於operator <和operator>的結果不會立即直觀,因此最好不要定義這些運算子。
建議:不要定義對您的類沒有意義的過載運算子。
但是,上述建議有一個共同的例外。如果我們想要對汽車列表進行排序怎麼辦?在這種情況下,我們可能希望過載比較運算子以返回您最有可能要排序的成員(或成員)。例如,過載的operator<對於 Cars可能會按字母順序基於品牌和型號進行排序。
標準庫中的一些容器類(包含其他類的集合的類)需要過載的operator<所以它們可以保持元素的排序。
以下是過載operator>,operator <,operator> =和operator <=的不同示例:
#include <iostream> class Cents { private: int m_cents; public: Cents(int cents) { m_cents = cents; } friend bool operator> (const Cents &c1, const Cents &c2); friend bool operator<= (const Cents &c1, const Cents &c2); friend bool operator< (const Cents &c1, const Cents &c2); friend bool operator>= (const Cents &c1, const Cents &c2); }; bool operator> (const Cents &c1, const Cents &c2) { return c1.m_cents > c2.m_cents; } bool operator>= (const Cents &c1, const Cents &c2) { return c1.m_cents >= c2.m_cents; } bool operator< (const Cents &c1, const Cents &c2) { return c1.m_cents < c2.m_cents; } bool operator<= (const Cents &c1, const Cents &c2) { return c1.m_cents <= c2.m_cents; } int main() { Cents dime(10); Cents nickle(5); if (nickle > dime) std::cout << "a nickle is greater than a dime.\n"; if (nickle >= dime) std::cout << "a nickle is greater than or equal to a dime.\n"; if (nickle < dime) std::cout << "a dime is greater than a nickle.\n"; if (nickle <= dime) std::cout << "a dime is greater than or equal to a nickle.\n"; return 0; }
這也非常簡單。
注意,這裡也有一些冗餘。operator>和operator <=是邏輯對立面,因此可以用另一個來定義。operator <和operator> =也是邏輯對立面,一個可以用另一個來定義。在這種情況下,我選擇不這樣做,因為函式定義非常簡單,函式名中的比較運算子與return語句中的比較運算子可以很好地對齊。
Quiz Time:
1)對於上面的Cents示例,根據其他過載運算子重寫運算子<和<=。
解決方案
#include <iostream>
class Cents
{
private:
int m_cents;
public:
Cents(int cents) { m_cents = cents; }
friend bool operator> (const Cents &c1, const Cents &c2);
friend bool operator<= (const Cents &c1, const Cents &c2);
friend bool operator< (const Cents &c1, const Cents &c2);
friend bool operator>= (const Cents &c1, const Cents &c2);
};
bool operator> (const Cents &c1, const Cents &c2)
{
return c1.m_cents > c2.m_cents;
}
bool operator>= (const Cents &c1, const Cents &c2)
{
return c1.m_cents >= c2.m_cents;
}
// <是> =的邏輯相反,所以我們可以> =並反轉
bool operator< (const Cents &c1, const Cents &c2)
{
return !(c1 >= c2);
}
// <= 是>的邏輯相反,所以我們可以做>並反轉結
bool operator<= (const Cents &c1, const Cents &c2)
{
return !(c1 > c2);
}
int main()
{
Cents dime(10);
Cents nickle(5);
if (nickle > dime)
std::cout << "a nickle is greater than a dime.\n";
if (nickle >= dime)
std::cout << "a nickle is greater than or equal to a dime.\n";
if (nickle < dime)
std::cout << "a dime is greater than a nickle.\n";
if (nickle <= dime)
std::cout << "a dime is greater than or equal to a nickle.\n";
return 0;
}
2)將過載的運算子<<和operator <新增到本課程頂部的Car類,以便以下程式編譯:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
std::vector<Car> v;
v.push_back(Car("Toyota", "Corolla"));
v.push_back(Car("Honda", "Accord"));
v.push_back(Car("Toyota", "Camry"));
v.push_back(Car("Honda", "Civic"));
std::sort(v.begin(), v.end()); // 要求超載operator<
for (auto &car : v)
std::cout << car << '\n'; //要求超載 operator<<
return 0;
}
該程式應產生以下輸出: (Honda,Accord) (Honda,Civic) (Toyota,Camry) (Toyota,Corolla) 解決方案:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
class Car
{
private:
std::string m_make;
std::string m_model;
public:
Car(std::string make, std::string model)
: m_make(make), m_model(model)
{
}
friend bool operator== (const Car &c1, const Car &c2);
friend bool operator!= (const Car &c1, const Car &c2);
friend std::ostream& operator<< (std::ostream& out, const Car & c)
{
out << '(' << c.m_make << ", " << c.m_model << ')';
return out;
}
// h/t to reader Olivier for this version of the function
friend bool operator<(const Car &c1, const Car &c2)
{
if (c1.m_make == c2.m_make) //如果汽車是一樣的...
return c1.m_model < c2.m_model; //然後比較 m_model
else
return c1.m_make < c2.m_make; // 否則比較兩個m_make
}
};
bool operator== (const Car &c1, const Car &c2)
{
return (c1.m_make == c2.m_make &&
c1.m_model == c2.m_model);
}
bool operator!= (const Car &c1, const Car &c2)
{
return !(c1 == c2);
}
int main()
{
std::vector<Car> v;
v.push_back(Car("Toyota", "Corolla"));
v.push_back(Car("Honda", "Accord"));
v.push_back(Car("Toyota", "Camry"));
v.push_back(Car("Honda", "Civic"));
std::sort(v.begin(), v.end()); // 要求超載 Car::operator<
for (auto &car : v)
std::cout << car << '\n'; // 要求超載Car::operator<<
return 0;
}