运算符重载是C++中的一项强大特性,它允许程序员为自定义类型(如类或结构体)重新定义标准运算符的行为,使得这些运算符能够适用于自定义类型的操作。这样做可以增强代码的可读性和表达力,使得代码更接近自然语言,同时保持了面向对象编程的封装性。
基本原则
- 保留原有语义:重载的运算符应当保持其原有的基本意义,比如加号
+
通常用于表示相加或组合的概念。 - 不要滥用:虽然运算符重载很灵活,但过度或不恰当的使用会使得代码难以理解和维护。
- 一致性:运算符的行为应与内置类型或大家公认的约定保持一致,以减少学习和使用的障碍。
- 明确性:确保重载的运算符在其上下文中具有明确的意义,避免引起混淆。
重载类型
- 二元运算符:如
+
、-
、*
、/
等,需要至少两个操作数。 - 一元运算符:如
++
、--
、!
等,只涉及一个操作数。 - 赋值运算符:如
=
,+=
,-=
,*=
,/=
等,有特殊的规则,比如需要考虑自赋值的情况。 - 转换运算符:如
operator T()
,允许类的对象隐式或显式转换为另一种类型。 - I/O流运算符:如
<<
、>>
,用于与标准输入输出流集成,增强类的可读性和可写性。 - 条件运算符:如
<
、>
、==
等,用于比较操作。 - 下标运算符
[]
:使得对象可以像数组那样通过索引访问。 - 函数调用运算符
()
:允许对象像函数一样被调用。
【1】运算符重载函数名格式
返回值 operator运算符(参数)
{
//函数体
}
【2】运算符重载的目的
让自己定义的类也能直接参与运算
运算符重载的要求:
- 不能创造运算符,必须对已有的运算符重载
- 不能更改运算符本身的功能,+运算重载后实现乘法运算
【3】运算符重载函数的格式
- 成员函数的格式:给哪个类重载运算符,就把重载函数定义为哪个类的成员函数
- 全局函数的格式:需要在类内声明全局函数为友元函数
成员函数版的运算符重载一定比全局函数版的运算符重载少一个参数,成员函数本身提供了一个类对象
【4】算数运算符的重载
算术运算都是双目运算:
格式:L # R ---->需要两个类对象作为参数
结果:右值
参数:运算过程中不需要修改操作数,可以定义为const
示例:
#include <iostream> class Complex { public: // 默认构造函数 Complex() : real(0), imag(0) {} // 带参数的构造函数 Complex(double r, double i) : real(r), imag(i) {} // 重载 "+" 运算符 Complex operator+(const Complex& other) const { return Complex(real + other.real, imag + other.imag); } // 显示复数的方法 void display() const { std::cout << real << " + " << imag << "i" << std::endl; } private: double real; // 实部 double imag; // 虚部 }; int main() { Complex num1(3, 4); // 创建复数 3 + 4i Complex num2(1, 2); // 创建复数 1 + 2i Complex sum = num1 + num2; // 使用重载的 "+" 运算符 std::cout << "Sum of the two complex numbers: "; sum.display(); // 输出相加后的复数 return 0; }
编辑
【5】赋值运算符的重载
operator= :拷贝赋值函数
+=、-=···运算符的重载
格式:L # R
结果:对左操作数的修改,是一个左值
参数:左操作数运算过程中可以修改,右操作数不能修改
示例:
// 赋值运算符重载 Complex& operator=(const Complex& other) { if (this != &other) { // 防止自我赋值 real = other.real; imag = other.imag; } return *this; }
【6】条件运算符的重载
< >·····
格式:L # R
结果:bool类型的真值或者假值
参数:运算过程中不需要修改操作数,可以定义为const
bool operator>(Complex &c1,Complex &c2)
{}
示例:
// 小于运算符重载 bool operator<(const Complex& other) const { return (real < other.real) || ((real == other.real) && (imag < other.imag)); }
【7】()运算符的重载
- 对()运算符,调用函数的性质重载
- 对()强转的性质重载 float a; int(a);
格式:operator 数据类型(){} ---->因为强转类型已经明确了返回值类型
示例:
// 下标运算符重载 double& operator[](int index) { if (index == 0) return real; else if (index == 1) return imag; else throw std::out_of_range("Index out of range for Complex number."); }
【8】自增自减运算符的重载
a++、 ++a、
前自增:
成员函数:Complex &operator++(){}
全局函数:Complex &operator++(Complex &c1){}
后自增: ----->需要使用哑元和前自增区分
成员函数:Complex &operator++(int){}
全局函数:Complex &operator++(Complex &c1,int){}
示例:
// 自增运算符前置版本 Complex& operator++() { ++real; ++imag; return *this; } // 自增运算符后置版本 Complex operator++(int) { Complex temp(*this); ++(*this); return temp; } // 自减运算符前置版本 Complex& operator--() { --real; --imag; return *this; } // 自减运算符后置版本 Complex operator--(int) { Complex temp(*this); --(*this); return temp; }
【9】不能重载的运算符
- sizeof()
- 成员访问运算符.
- 指针访问运算符 * ---->对指针访问
- :: 域限定符
- a?a:b