c++——运算符的重载
目录
一、 运算符重载基本语法和规则
1.运算符重载的定义
2.运算符重载的基本语法
3.运算符的重载规则
二、成员函数的重载和非成员函数的重载
1.成员函数重载
2.非成员函数的重载
三、具体运算符的重载
1.重载+
(1)引入——实现复数类的Add函数
(2)使用operator实现+重载
2.重载-
3.重载=
(1)注意
(2)实现要点
(3)对比值返回和引用返回
4.重载前置++
5.重载后置++
6.重载<
四、常见运算符的const总结
一、 运算符重载基本语法和规则
1.运算符重载的定义
允许用户为自定义类型重新定义运算符的行为,使得对象可以像内置类型一样进行运算。
2.运算符重载的基本语法
返回类型 operator运算符(参数列表) {// 实现逻辑
}
3.运算符的重载规则
①不能创造新运算符:只能重载已有的运算符(如 +
, ==
, []
, ()......
)
注意:只有极少部分运算符不可以被重载,比如:三目运算符、成员操作符、作用域操作符、sizeof操作符、typeid类型信息运算符。
②至少有一个操作数是自定义类型:不能为内置类型重载运算符。
③保持运算符原有语义:避免滥用(如用 +
实现减法)。
二、成员函数的重载和非成员函数的重载
1.成员函数重载
左侧操作数:隐式绑定到 this
对象。
参数数量:比运算符的操作数少一个(如二元运算符只需一个参数)。
2.非成员函数的重载
所有操作数:显式声明为参数。
常用场景:左侧操作数不是当前类(如 operator<<
)或需要隐式类型转换。
注意:非成员函数重载若需要访问私有成员,需声明为友元。
三、具体运算符的重载
1.重载+
(1)引入——实现复数类的Add函数
判断以下5种方法的正确性:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Complex
{
private:double Real, Image;
public:Complex(double r = 0.0, double i = 0.0) :Real(r), Image(i) //构造函数 {cout << "Create object: " << this << endl;}Complex(const Complex& com) :Real(com.Real), Image(com.Image)//拷贝构造函数{cout << "Copy Create object: " << this << endl;}~Complex() //析构函数{cout << " Destory Object:" << this << endl;}void print() const // 普通方法和常方法都可以调用{cout << "Real=" << Real << 't' << "Image=" << Image << endl;}/*第一种写法,传递的参数是副本(调用拷贝构造函数创建实参的副本),需要创建额外的空间,支持常量对象*/Complex Add(Complex cx) {return Complex(this->Real + cx.Real, this->Image + cx.Image);}/*第二种写法,传递的参数是引用,不需要拷贝实参的副本,函数效率更高,不支持常量的对象*//*Complex Add(Complex& cx) {return Complex(this->Real + cx.Real, this->Image + cx.Image);}*//*第三种写法,传递的参数是常引用,表示被引用的实参是不可改变的,不支持常量对象*/Complex Add(const Complex& cx){return Complex(this->Real + cx.Real, this->Image + cx.Image);}//第四种写法,普通方法和常方法都可以调用,比较适用Complex Add(const Complex& cx) const //常成员函数{return Complex(this->Real + cx.Real, this->Image + cx.Image);}/*第五种写法,错误注意:不能返回一个临时对象的引用。因为函数执行完毕后,临时对象就会被销毁,此时引用指向的是一个已经不存在的对象。*/Complex& Add(const Complex& cx) const{return Complex(this->Real + cx.Real, this->Image + cx.Image);}
};
int main()
{const Complex ca(1, 2), cb(3, 4); //常对象,不允许修改对象的值Complex cc;cc = ca.Add(cb); //等价于//cc = Add(&ca, cb);return 0;
}
解释上述5种方法:
1.Complex Add(Complex cx) ——值传递,但需要拷贝实参的副本,效率低下。(√)
2.Complex Add(Complex& cx) ——引用传递,不需要拷贝的实参的副本,函数效率更高,但不能接受常量对象作为参数(但不能被常对象调用) (×)
3.Complex Add(const Complex& cx)——常引用传递,不允许修改实参的值,也不能被常对象调用。(×)
4. Complex Add(const Complex& cx) const ——常引用+常方法(普通方法和常方法都可以调用)(√)
5.Complex& Add(const Complex& cx) const——返回临时对象的引用。 (×)
注意:不能返回一个临时对象的引用。因为函数执行完毕后,临时对象就会被销毁,此时引用指向的是一个已经不存在的对象。
总结:一般使用引用作为函数参数,可以避免拷贝,但要注意不要返回临时变脸的引用。
(2)使用operator实现+重载
①常对象与常对象相加
//运算符的重载
class Complex
{
private:double Real, Image;
public:Complex(double r = 0.0, double i = 0.0) :Real(r), Image(i) //构造函数 {cout << "Create object: " << this << endl;}Complex(const Complex& com) :Real(com.Real), Image(com.Image)//拷贝构造函数{cout << "Copy Create object: " << this << endl;}~Complex() //析构函数{cout << " Destory Object:" << this << endl;}void print() const // 普通方法和常方法都可以调用{cout << "Real=" << Real << 't' << "Image=" << Image << endl;}//使用Add实现常对象的方法Complex Add(const Complex& cx) const //常成员函数{return Complex(this->Real + cx.Real, this->Image + cx.Image);}//重载+ Complex operator+(const Complex &cx) const{return Complex(this->Real + cx.Real, this->Image + cx.Image);}};
int main()
{const Complex ca(1, 2), cb(3, 4); //常对象,不允许修改对象的值Complex cc;cc = ca.Add(cb); //等价于//cc = Add(&ca, cb);return 0;
}
2.重载-
与重载+原理一样(*、/ 原理也相同)
3.重载=
(1)注意
如果在类的定义中没有显式给出赋值运算符重载函数时,系统会自动调用缺省的赋值函数。
(2)实现要点
①返回引用:为了支持连续赋值(例如a = b = c
),赋值运算符应返回*this
的引用。
②检查自赋值:在进行赋值操作之前,要先检查this
和other
是否为同一个对象,避免不必要的操作甚至错误。
(3)对比值返回和引用返回
重载=
1.为什么采用引用返回,不采用值返回?
原因:赋值操作要支持连续赋值,支持链式调用,避免值拷贝造成的大量开销。2.避免将赋值重载函数设计为常方法
常方法会限制this,使其内容不被修改。而赋值操作,需要修改值。
4.重载前置++
前置++返回自增后的引用,支持链式操作,不创建临时对象,效率高。
5.重载后置++
后置++返回自增前的拷贝,存在拷贝构造和析构的开销,效率低。
6.重载<
主要用于运算符的比较,返回一个布尔值。
7.重载类型强转运算符
将一个类型的值转换为另一个类型。
四、常见运算符的const总结
(1)不修改对象状态:声明为 const,允许对常量对象使用。
(2)修改对象状态:不能声明为 const
。
(3)返回当前对象引用:若修改对象(如 +=
),不声明为 const
;若不修改,声明为 const
。
如图所示:
运算符类型 | 是否需要 const | 示例代码 |
---|---|---|
比较运算符(== ) | ✅ 必须 | bool operator==(const T&) const |
算术运算符(+ ) | ✅ 推荐 | T operator+(const T&) const |
赋值运算符(= ) | ❌ 不能 | T& operator=(const T&) |
复合赋值(+= ) | ❌ 不能 | T& operator+=(const T&) |
前置自增(++a ) | ❌ 不能 | T& operator++() |
后置自增(a++ ) | ❌ 通常不 | T operator++(int) |
类型转换(double ) | ✅ 必须 | operator double() const |
下标运算符([] ) | 取决于是否修改 | T& operator[](int) (非 const 版本) |