操作符重载 2025-09-29

操作符重载的作用

使我们可以像基本数据类型那样用运算符;
仿函数是建立在操作符重载的基础上的;
stl中容器的算法也是建立在操作符重载的基础上的;

首先我个人认为去写操作符重载要掌握的最重要的原则是:你写的这个重载操作符要传入几个参数。
其原则是看这个操作符重载是不是当前类的成员函数,如果是就只需要传一个参数(隐含参数:左操作数 (a) 通过 this指针传递);如果是类外或者友元等非成员函数那需要传两个参数

下面写几个案例

举例说明

下面是不能两中方式一起写的,这会造成编译错误(二义性错误)
对于 +这类不修改左操作数、通常返回新对象的对称性运算符,更推荐使用非成员函数(友元)形式。这样做还有一个好处:如果你希望支持 (整数 + Complex对象)这样的表达式,非成员函数是必须的,因为整数不是你的类类型,不能作为成员函数的调用者。
如果 operator+是成员函数,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. 算术运算符与复合赋值运算符 (+, +=)

#include <iostream>
class Complex {
private:
    double real;
    double imag;
public:
    Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}

    // 复合赋值运算符 +=,通常作为成员函数(修改左操作数)
    Complex& operator+=(const Complex& rhs) {
        real += rhs.real;
        imag += rhs.imag;
        return *this; // 返回引用以支持链式赋值 (a += b) += c
    }

    // 提供友元函数形式,以便支持左操作数为非本类对象的情况
    friend Complex operator+(const Complex& lhs, const Complex& rhs);
};

// 算术运算符 +,作为非成员友元函数(不修改操作数,生成新对象)
Complex operator+(const Complex& lhs, const Complex& rhs) {
    return Complex(lhs.real + rhs.real, lhs.imag + rhs.imag);
    // 也可以利用已实现的 += 来提升效率:Complex result(lhs); return result += rhs;
}

int main() {
    Complex a(1.0, 2.0), b(3.0, 4.0);
    Complex c = a + b; // 调用 operator+(a, b)
    a += b;            // 调用 a.operator+=(b)
    return 0;
}

2. 关系运算符 (==, !=)

class Complex {
    // ... 其他成员同上
public:
    // 关系运算符 ==,通常重载为友元函数
    friend bool operator==(const Complex& lhs, const Complex& rhs) {
        return (lhs.real == rhs.real) && (lhs.imag == rhs.imag);
    }

    // 关系运算符 !=,通常利用 == 来实现
    friend bool operator!=(const Complex& lhs, const Complex& rhs) {
        return !(lhs == rhs);
    }
};

3. 输入与输出运算符 (>>, <<)

class Complex {
    // ... 其他成员同上
public:
    // 输入输出运算符必须重载为非成员函数
    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. 下标运算符 ([])

下标运算符 []必须重载为类的成员函数。为了同时支持常量对象和非常量对象的使用,通常需要提供两个版本。

class MyArray {
private:
    int data[100];
    size_t size;
public:
    MyArray(size_t s = 100) : size(s) {}

    // 非常量版本:允许通过下标修改数组元素
    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;        // 调用非常量版本,可以赋值
    std::cout << arr[10]; // 调用非常量版本,可以读取

    const MyArray const_arr;
    // const_arr[10] = 50; // 错误!调用常量版本,不能赋值
    std::cout << const_arr[10]; // 正确,调用常量版本,可以读取
    return 0;
}

5. 递增与递减运算符 (++, --)

递增和递减运算符有前置和后置两种形式,需要通过参数来区分。

class Counter {
private:
    int count;
public:
    Counter(int c = 0) : count(c) {}

    // 前置 ++:无参数,返回递增后的引用
    Counter& operator++() {
        ++count;
        return *this;
    }

    // 后置 ++:int 参数仅用于区分,无实际意义,返回递增前的副本(值)
    Counter operator++(int) {
        Counter temp = *this; // 保存原值
        ++(*this);           // 利用前置 ++ 实现递增
        return temp;         // 返回原值
    }

    // 前置 -- 和后置 -- 类似
    Counter& operator--() {
        --count;
        return *this;
    }
    Counter operator--(int) {
        Counter temp = *this;
        --(*this);
        return temp;
    }
};

stl容器算法 (自定义排序规则)

使用重载的 < 运算符进行排序

#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;
}

使用仿函数

#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());

——

条件查找和计数 也常自定义逻辑

同样可以使用类成员函数重载操作符,也可以使用自定义仿函数



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};
    //统计满足条件的数量有多少个(其实用lamada表达式显得逻辑更清晰,但用仿函数增加了复用性)
    int count=std::count_if(scores.begin(),scores.end(),GreaterThan(80));
    std::cout<<"大于80分的数量: "<<count<<std::endl;

    //使用find_if 在范围内查找第一个满足特定条件的元素 返回的是迭代器
    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>

// 自定义仿函数:将元素乘以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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容