上期回顾: 【C++】指针和引用
个人主页:C_GUIQU
归属专栏:C++
目录
正文
1. 操作符重载和运算符重载的基本概念
定义:在C++中,操作符重载(Operator Overloading)和运算符重载实际上是同一个概念,它允许程序员为自定义的数据类型重新定义已有的运算符的行为,使得这些运算符能够像操作内置数据类型一样自然地操作自定义类型的对象。
例如,对于自定义的复数类 Complex
,我们希望能够像使用内置的算术运算符操作整数或浮点数那样,使用 +
、-
、*
、/
等运算符来操作复数对象。通过运算符重载,就可以实现这种需求,让代码更加直观和易于理解。
2. 为什么要进行操作符重载
2.1 提高代码的可读性和可维护性
当处理自定义数据类型时,如果没有运算符重载,可能需要调用专门的函数来实现类似加法、减法等操作。例如,对于复数类,可能需要定义 addComplex
、subtractComplex
等函数来实现复数的加法和减法运算。而使用运算符重载后,可以直接使用 +
和 -
运算符,代码看起来更加清晰,符合人们日常的数学运算习惯,从而提高了代码的可读性和可维护性。
2.2 使自定义类型的操作更符合直觉
以向量类 Vector
为例,我们希望能够通过 +
运算符来实现向量的加法运算,通过 *
运算符来实现向量与标量的乘法运算等。运算符重载使得这些操作可以按照我们期望的方式进行,就像在数学中对向量进行运算一样,让代码的逻辑更加直观。
3. 如何进行操作符重载
3.1 重载运算符的函数格式
运算符重载是通过定义特殊的成员函数或非成员函数来实现的。对于二元运算符(如 +
、-
、*
、/
等,需要两个操作数),其重载函数的一般格式如下:
作为成员函数重载
如果将运算符重载为类的成员函数,函数的一般形式为:
返回值类型 operator运算符符号(参数列表) {
// 函数体,实现运算符的具体操作
}
例如,对于一个复数类 Complex
,重载 +
运算符作为成员函数的示例如下:
class Complex {
private:
double real;
double imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {
}
Complex operator+(const Complex& other) {
Complex result;
result.real = this->real + other.real;
result.imag = this->imag + other.imag;
return result;
}
};
在上述代码中,operator+
是重载 +
运算符的成员函数,它接受一个 const Complex&
类型的参数,表示要与当前对象相加的另一个复数对象。在函数体中,实现了将两个复数的实部和虚部分别相加的操作,并返回一个新的复数对象作为相加的结果。
作为非成员函数重载
对于一些运算符,也可以将其重载为非成员函数。其一般形式为:
返回值类型 operator运算符符号(参数列表) {
// 函数体,实现运算符的具体操作
}
例如,同样对于复数类 Complex
,重载 +
运算符作为非成员函数的示例如下:
class Complex {
private:
double real;
double imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {
}
friend Complex operator+(const Complex& a, const Complex& b);
};
Complex operator+(const Complex& a, const Complex& b) {
Complex result;
result.real = a.real + b.real;
result.imag = a.imag + b.imag;
return result;
}
在上述代码中,首先在类 Complex
中声明了 operator+
作为友元函数(通过 friend
关键字),以便它可以访问类的私有成员。然后在类外定义了 operator+
函数,其参数是两个要相加的复数对象 a
和 b
,在函数体中实现了与成员函数重载类似的相加操作,并返回新的复数对象。
3.2 重载运算符的规则和注意事项
不能创建新的运算符
只能对C++中已有的运算符进行重载,不能自己创造新的运算符符号来进行重载。例如,不能定义一个全新的运算符符号如 @
并进行重载(除非它是通过宏定义等特殊方式模拟出来的,但这不是真正意义上的运算符重载)。
保持运算符的原有语义
虽然可以重新定义运算符的操作,但应该尽量保持运算符的原有语义。例如,+
运算符通常表示加法运算,在重载时也应该使其实现类似加法的操作,而不是赋予它完全不同的含义,否则会让代码的可读性变差。
操作数的类型和个数要匹配
在重载运算符时,要根据运算符的原有特性来确定操作数的类型和个数。比如,二元运算符需要两个操作数,一元运算符需要一个操作数。并且,操作数的类型应该与重载函数中定义的参数类型相匹配。
某些运算符有特殊的重载规则
一些运算符有特殊的重载规则,例如:
=
: 赋值运算符通常需要返回一个引用,以便支持链式赋值,如a = b = c;
。[]
: 下标运算符通常用于访问容器类中的元素,重载时要注意正确处理索引越界等问题。()
: 函数调用运算符通常用于使对象可以像函数一样被调用,在重载时要考虑函数的参数传递、返回值等方面。
4. 常见运算符的重载示例
4.1 算术运算符
以复数类为例,展示 +
、-
、*
、/
等算术运算符的重载。
+运算符重载
前面已经给出了复数类 Complex
中 +
运算符作为成员函数和非成员函数重载的示例,这里不再赘述。
-运算符重载
作为成员函数重载 -
运算符的示例如下:
class Complex {
private:
double real;
double imag;
public:
Complex(double r =