操作符重載的作用
使我們可以像基本數(shù)據(jù)類型那樣用運算符;
仿函數(shù)是建立在操作符重載的基礎(chǔ)上的;
stl中容器的算法也是建立在操作符重載的基礎(chǔ)上的;
首先我個人認為去寫操作符重載要掌握的最重要的原則是:你寫的這個重載操作符要傳入幾個參數(shù)。
其原則是看這個操作符重載是不是當(dāng)前類的成員函數(shù),如果是就只需要傳一個參數(shù)(隱含參數(shù):左操作數(shù) (a) 通過 this指針傳遞);如果是類外或者友元等非成員函數(shù)那需要傳兩個參數(shù)
下面寫幾個案例
舉例說明
下面是不能兩中方式一起寫的,這會造成編譯錯誤(二義性錯誤)
對于 +這類不修改左操作數(shù)、通常返回新對象的對稱性運算符,更推薦使用非成員函數(shù)(友元)形式。這樣做還有一個好處:如果你希望支持 (整數(shù) + Complex對象)這樣的表達式,非成員函數(shù)是必須的,因為整數(shù)不是你的類類型,不能作為成員函數(shù)的調(diào)用者。
如果 operator+是成員函數(shù),5 + c1將無法編譯。(c1是Complex的對象)
class Complex{
public:
Complex operator+(const Complex& rightOperand) const
{
return Complex(real+rightOperand.real,imag+rightOperand.imag);
}
friend Complex operator+(const Complex& leftOperand,const Complex& rightOperand);
private:
double real,imag;
};
Complex operator+(const Complex& leftOperand,const Complex& rightOperand)
{
return Complex(leftOperand.real+rightOperand.real,leftOperand.imag+rightOperand.imag);
}
1. 算術(shù)運算符與復(fù)合賦值運算符 (+, +=)
#include <iostream>
class Complex {
private:
double real;
double imag;
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
// 復(fù)合賦值運算符 +=,通常作為成員函數(shù)(修改左操作數(shù))
Complex& operator+=(const Complex& rhs) {
real += rhs.real;
imag += rhs.imag;
return *this; // 返回引用以支持鏈式賦值 (a += b) += c
}
// 提供友元函數(shù)形式,以便支持左操作數(shù)為非本類對象的情況
friend Complex operator+(const Complex& lhs, const Complex& rhs);
};
// 算術(shù)運算符 +,作為非成員友元函數(shù)(不修改操作數(shù),生成新對象)
Complex operator+(const Complex& lhs, const Complex& rhs) {
return Complex(lhs.real + rhs.real, lhs.imag + rhs.imag);
// 也可以利用已實現(xiàn)的 += 來提升效率:Complex result(lhs); return result += rhs;
}
int main() {
Complex a(1.0, 2.0), b(3.0, 4.0);
Complex c = a + b; // 調(diào)用 operator+(a, b)
a += b; // 調(diào)用 a.operator+=(b)
return 0;
}
2. 關(guān)系運算符 (==, !=)
class Complex {
// ... 其他成員同上
public:
// 關(guān)系運算符 ==,通常重載為友元函數(shù)
friend bool operator==(const Complex& lhs, const Complex& rhs) {
return (lhs.real == rhs.real) && (lhs.imag == rhs.imag);
}
// 關(guān)系運算符 !=,通常利用 == 來實現(xiàn)
friend bool operator!=(const Complex& lhs, const Complex& rhs) {
return !(lhs == rhs);
}
};
3. 輸入與輸出運算符 (>>, <<)
class Complex {
// ... 其他成員同上
public:
// 輸入輸出運算符必須重載為非成員函數(shù)
friend std::ostream& operator<<(std::ostream& os, const Complex& c) {
os << c.real << " + " << c.imag << "i";
return os; // 返回流引用以支持鏈式操作 cout << a << b;
}
friend std::istream& operator>>(std::istream& is, Complex& c) {
is >> c.real >> c.imag;
return is; // 返回流引用以支持鏈式操作 cin >> a >> b;
}
};
4. 下標運算符 ([])
下標運算符 []必須重載為類的成員函數(shù)。為了同時支持常量對象和非常量對象的使用,通常需要提供兩個版本。
class MyArray {
private:
int data[100];
size_t size;
public:
MyArray(size_t s = 100) : size(s) {}
// 非常量版本:允許通過下標修改數(shù)組元素
int& operator[](size_t index) {
if (index >= size) throw std::out_of_range("Index out of range");
return data[index];
}
// 常量版本:用于常量對象,只允許讀取,返回 const 引用
const int& operator[](size_t index) const {
if (index >= size) throw std::out_of_range("Index out of range");
return data[index];
}
};
int main() {
MyArray arr;
arr[10] = 42; // 調(diào)用非常量版本,可以賦值
std::cout << arr[10]; // 調(diào)用非常量版本,可以讀取
const MyArray const_arr;
// const_arr[10] = 50; // 錯誤!調(diào)用常量版本,不能賦值
std::cout << const_arr[10]; // 正確,調(diào)用常量版本,可以讀取
return 0;
}
5. 遞增與遞減運算符 (++, --)
遞增和遞減運算符有前置和后置兩種形式,需要通過參數(shù)來區(qū)分。
class Counter {
private:
int count;
public:
Counter(int c = 0) : count(c) {}
// 前置 ++:無參數(shù),返回遞增后的引用
Counter& operator++() {
++count;
return *this;
}
// 后置 ++:int 參數(shù)僅用于區(qū)分,無實際意義,返回遞增前的副本(值)
Counter operator++(int) {
Counter temp = *this; // 保存原值
++(*this); // 利用前置 ++ 實現(xiàn)遞增
return temp; // 返回原值
}
// 前置 -- 和后置 -- 類似
Counter& operator--() {
--count;
return *this;
}
Counter operator--(int) {
Counter temp = *this;
--(*this);
return temp;
}
};
stl容器算法 (自定義排序規(guī)則)
使用重載的 < 運算符進行排序
#include <algorithm>
#include <vector>
#include <string>
struct Person
{
std::string name;
int age;
bool operator<(const Person& other) const
{
return age<other.age;
}
};
int main()
{
std::vector<Person> people = {{"Alice", 25}, {"Bob", 20}, {"Charlie", 30}};
std::sort(people.begin(),people.end());
return 0;
}
使用仿函數(shù)
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
std::vector<int> numbers={3,1,4,1,5,9,2,6};
std::sort(numbers.begin(),numbers.end(),std::greator<int>());
struct LengthCompare
{
bool operator()(const std::string& a,const std::string& b) const
{
return a.length()<b.length();
}
}
std::vector<std::string> words={"apple","a","banana","cat"};
std::sort(words.begin(),words.end(),LengthCompare());
——
條件查找和計數(shù) 也常自定義邏輯
同樣可以使用類成員函數(shù)重載操作符,也可以使用自定義仿函數(shù)
class GreaterThan
{
public:
GreaterThan(int threshold):threshold_(threshold) {}
bool operator()(int x) const {return x>threshold_;}
private:
int threshold_;
};
int main()
{
std::vector<int> scores={85,92,76,60,99,45};
//統(tǒng)計滿足條件的數(shù)量有多少個(其實用lamada表達式顯得邏輯更清晰,但用仿函數(shù)增加了復(fù)用性)
int count=std::count_if(scores.begin(),scores.end(),GreaterThan(80));
std::cout<<"大于80分的數(shù)量: "<<count<<std::endl;
//使用find_if 在范圍內(nèi)查找第一個滿足特定條件的元素 返回的是迭代器
auto it_25=std::find_if(socres.begin(),socres.end(),[](int n){return n==25;}
if(it_25!=scores.end())
{
std::cout << "第一個等于25的元素: " << *it_25 << ",位于索引 " << (it_25 - scores.begin()) << std::endl; // 輸出: 第一個等于25的元素: 25,位于索引 1
}
return 0;
}
變換元素
#include <algorithm>
#include <vector>
#include <iostream>
// 自定義仿函數(shù):將元素乘以2
class MultiplyByTwo {
public:
int operator()(int x) const { return x * 2; }
};
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
std::vector<int> result(vec.size());
std::transform(vec.begin(), vec.end(), result.begin(), MultiplyByTwo());
// result = {2, 4, 6, 8, 10} [1,3](@ref)
return 0;
}