- 首先 c++ 過載運算子只能在 class 或者結構體中
- 以下面的程式碼為例
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 9;
struct Book
{
int a, b, c;
bool operator<(const Book &x) const
{
if (a != x.a)
return a < x.a;
if (b != x.b)
return b < x.b;
return c < x.c;
}
} p[N];
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> p[i].a >> p[i].b >> p[i].c;
sort(p + 1, p + n + 1);
for (int i = 1; i <= n; ++i)
cout << p[i].a << " " << p[i].b << " " << p[i].c << "\n";
return 0;
}
在這段程式碼中,定義了一個
Book
結構體,其中包含三個整數型別的成員變數a
、b
和c
。重點在於對<
運算子的過載,這是在 C++中自定義型別排序邏輯的一種常見做法。透過過載<
運算子,我們可以使Book
型別的物件能夠使用標準庫函式std::sort
進行排序。
對 <
運算子的過載
bool operator<(const Book &x) const
{
if (a != x.a)
return a < x.a;
if (b != x.b)
return b < x.b;
return c < x.c;
}
對程式碼的解釋
這段程式碼過載了 <
運算子,使得兩個 Book
物件可以直接比較。這裡的比較邏輯是:
-
首先比較
a
欄位:如果當前物件的a
欄位不等於另一個物件的a
欄位,則比較這兩個a
欄位的大小。如果當前物件的a
小於另一個物件的a
,則返回true
,表示當前物件應排在另一個物件之前;否則,返回false
。 -
然後比較
b
欄位:如果a
欄位相等,接下來比較b
欄位。邏輯與比較a
欄位相同。 -
最後比較
c
欄位:如果a
和b
欄位都相等,最後比較c
欄位,邏輯也相同。
主函式 main
在 main
函式中,首先透過 ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
禁用 C 和 C++標準庫之間的同步,從而加速輸入輸出操作。
接著,讀入整數 n
,表示 Book
物件的數量。透過一個迴圈,讀取每個 Book
物件的 a
、b
、c
欄位值。
使用 std::sort
函式,按照過載的 <
運算子定義的邏輯,對陣列 p
中從索引 1
到 n
(包含)的 Book
物件進行排序。
最後,透過另一個迴圈,按排序後的順序輸出每個 Book
物件的 a
、b
、c
欄位。
總結
透過過載 <
運算子,該程式碼實現了 Book
結構體物件的自定義排序邏輯。這種方法使得 Book
物件可以直接使用 std::sort
等標準庫演算法進行排序,提供了一種靈活且強大的方式來定義物件間的排序規則。
這一行程式碼 bool operator<(const Book &x) const
是在 C++中對 <
運算子進行過載的宣告,具體到 Book
結構體的上下文中。這個運算子過載使得可以直接比較兩個 Book
型別的物件。下面詳細解釋這段程式碼的各個部分:
詳細解釋 bool operator<(const Book &x) const,以及為什麼能在結構體內對運算子進行過載,vector 是否可以完成
解釋
-
bool
:這是函式的返回型別,表示該運算子過載函式返回一個布林值,用於指示呼叫物件是否小於傳入的引數物件。 -
operator<
:這指明正在被過載的是<
運算子。 -
(const Book &x)
:這是函式的引數列表,表示該函式接受一個型別為const Book&
的引數。const
保證傳入的物件x
不會在函式中被修改,&
表示傳遞的是物件的引用,避免了物件的複製,提高了效率。 -
const
(在引數列表後):這個const
表示該成員函式不會修改呼叫它的物件的狀態。這是常量成員函式的標記,確保了在該函式內部不能修改任何成員變數(除了那些被宣告為mutable
的成員變數)。
為什麼能在結構體內對運算子進行過載?
在 C++中,結構體(struct
)與類(class
)非常相似,唯一的區別是預設的訪問許可權:struct
的成員預設是公開的(public
),而 class
的成員預設是私有的(private
)。因此,你可以在結構體內部定義成員函式,包括運算子過載函式,就像在類中一樣。這提供了一種定義如何透過標準運算子對自定義型別進行操作的方式,使得自定義型別的使用更加直觀和自然。
vector
可以完成運算子過載嗎?
std::vector
是 C++標準模板庫(STL)的一部分,它是一個模板類,不是使用者定義的型別,因此你不能為 std::vector
直接新增運算子過載。運算子過載需要在類或結構體的定義內部進行。然而,你可以對儲存在 vector
中的自定義型別(如 Book
)進行運算子過載,就像上面的例子那樣。然後,你可以利用這些過載來對 vector<Book>
進行排序等操作,因為 std::sort
等函式會使用這些過載來比較 vector
中的元素。
總之,運算子過載在結構體或類內部定義,使得這些自定義型別可以以一種直觀和自然的方式使用運算子。雖然不能直接為 std::vector
這樣的模板類過載運算子,但可以透過過載儲存在其中的自定義型別的運算子來實現間接的效果。
引數是如何被呼叫
在 C++中,當對運算子進行過載並使用這個過載運算子比較兩個物件時,引數的呼叫遵循特定的規則。以 bool operator<(const Book &x) const
為例,這裡解釋如何呼叫這個過載的 <
運算子以及引數是如何被傳遞的。
運算子過載函式的呼叫
假設有兩個 Book
型別的物件:book1
和 book2
。當你使用 book1 < book2
這樣的表示式時,這實際上是在呼叫 book1
的 operator<
函式,並將 book2
作為引數傳遞給這個函式。
Book book1, book2;
// 假設book1和book2已經被適當初始化
if (book1 < book2) {
// 邏輯處理
}
這個表示式等價於直接呼叫:
if (book1.operator<(book2)) {
// 邏輯處理
}
引數的傳遞
-
物件
book1
:作為比較操作的呼叫方,book1
的狀態不會被修改,因為operator<
被宣告為const
。這意味著在該函式內部不能修改book1
的任何成員變數。 -
物件
book2
:作為引數傳遞給operator<
函式。透過使用const Book &x
作為引數型別,book2
是以引用的方式傳遞的,同時保證了在operator<
函式內部不會修改book2
。使用引用傳遞避免了不必要的物件複製,提高了效率。同時,const
修飾符確保了函式內部不能修改傳入物件的狀態,這是一種良好的實踐,可以保護函式外部的資料不被意外修改。
總結
在 C++中,當你對過載的運算子進行呼叫時,呼叫物件作為運算子函式的隱式呼叫方(相當於函式的 this
指標指向的物件),而其他引數則根據運算子函式的宣告被顯式傳遞。透過這種方式,C++允許開發者定義型別如何響應標準運算子,既保持了程式碼的直觀性,又提供了強大的自定義能力。
在提供的程式碼片段中,<
運算子被過載用於 Book
結構體,使得 Book
物件可以被直接比較。這個過載的運算子實際上被使用在 main
函式中的 sort
函式呼叫裡:
sort(p + 1, p + n + 1);
這行程式碼使用 std::sort
來對 Book
型別的陣列 p
進行排序,範圍從 p[1]
到 p[n]
(注意 C++中陣列預設是從0開始索引的,但這裡從1開始使用,可能是基於特定的需求或習慣)。std::sort
函式內部會多次比較陣列中的元素來確定它們的排序順序。當 std::sort
需要比較兩個 Book
物件時(例如,決定哪個物件應該排在前面),它就會呼叫我們過載的 <
運算子。
這種比較邏輯允許 std::sort
根據 Book
物件的 a
、b
和 c
成員變數的值來排序這些物件。具體的比較邏輯首先比較 a
值,如果 a
值相同,則比較 b
值,如果 b
值也相同,則最後比較 c
值。這樣,std::sort
可以根據過載的 <
運算子正確地排序 Book
陣列。
總結
<
運算子的過載在 Book
物件陣列的排序中發揮了作用,即在 std::sort
函式內部被隱式呼叫以確定陣列中元素的順序。這展示了運算子過載在自定義型別排序中的強大能力,使得自定義型別可以像內建型別那樣,透過標準庫演算法進行有效的排序和比較。