C++ 重载运算符:理解与应用
介绍
在 C++ 中,运算符重载是一种让类或枚举类型的实例表现出内置类型的行为的方式。换言之,我们可以自定义运算符的行为,使其适用于我们创建的新类型。
运算符重载的主要优点是提高代码的可读性和可写性。当我们使用熟悉的运算符如 +
或 -
对自定义类型进行操作时,代码将更具直观性,比调用某些方法更容易理解。
然而,如果运算符重载不当,也可能导致代码难以理解。因此,必须谨慎使用运算符重载。
示例项目:复数类
让我们通过一个示例来了解运算符重载。我们将创建一个表示复数的类,并为其重载某些运算符。
复数是具有实部和虚部的数字,可以表示为 a + bi
,其中 a
是实部,b
是虚部,i
是虚数单位。
首先,让我们定义复数类:
class Complex {
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
private:
double real;
double imag;
};
这是一个基础的类,具有两个私有成员(实部和虚部),并有一个构造函数。
重载运算符
现在,让我们为这个类重载 +
和 -
运算符。我们将通过添加成员函数 operator+
和 operator-
来实现。
class Complex {
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
Complex operator+(const Complex& rhs) const {
return Complex(real + rhs.real, imag + rhs.imag);
}
Complex operator-(const Complex& rhs) const {
return Complex(real - rhs.real, imag - rhs.imag);
}
private:
double real;
double imag;
};
我们可以看到,这两个运算符函数返回了一个新的 Complex
对象,该对象是两个复数的加和或差。这符合我们对 +
和 -
运算符的期望。
扩展我们的 Complex
类来重载前缀和后缀的 ++
和 --
运算符。
前缀 ++ 和 –
前缀 ++
和 --
运算符在 C++ 中被定义为增加或减少变量的值,并返回改变后的变量。我们可以对 Complex
类进行如下修改以实现前缀 ++
和 --
运算符的重载:
class Complex {
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
// ...
Complex& operator++() { // 前置 ++
++real;
return *this;
}
Complex& operator--() { // 前置 --
--real;
return *this;
}
private:
double real;
double imag;
};
这里,我们假设复数的自增和自减操作只影响其实部。
后缀 ++ 和 –
后缀 ++
和 --
运算符稍微复杂一些,因为它们在改变变量的值之后返回改变前的值。这意味着我们需要在改变值之前保存原始值。C++ 通过接受一个表示 “哑元” 的 int
参数来区分后缀版本和前缀版本。让我们将这些运算符添加到 Complex
类中:
class Complex {
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
// ...
Complex operator++(int) { // 后置 ++
Complex temp = *this;
++real;
return temp;
}
Complex operator--(int) { // 后置 --
Complex temp = *this;
--real;
return temp;
}
private:
double real;
double imag;
};
现在,我们的 Complex
类可以处理 ++
和 --
的前缀和后缀版本。同样,我们只考虑对复数的实部进行操作。
当我们使用输入输出流(<<
和 >>
)运算符时,我们可以定制类对象的输入和输出行为。让我们为 Complex
类添加对输入和输出流运算符的重载。
输出运算符重载 <<
输出运算符 <<
用于将对象的值写入输出流,例如 cout
。我们可以使用 ostream
类作为输出流的类型,将 Complex
对象的实部和虚部输出到流中。下面是重载输出运算符 <<
的示例代码:
#include <iostream>
class Complex {
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
// ...
friend std::ostream& operator<<(std::ostream& os, const Complex& c) {
os << "(" << c.real << " + " << c.imag << "i)";
return os;
}
private:
double real;
double imag;
};
我们使用 friend
关键字将重载函数声明为友元函数,这样它就可以访问 Complex
类的私有成员变量。在重载函数中,我们使用流插入运算符 <<
将复数的实部和虚部输出到流中,然后返回输出流。
输入运算符重载 >>
类似地,输入运算符 >>
用于从输入流(例如 cin
)中读取对象的值。我们可以使用 istream
类作为输入流的类型,并从流中提取实部和虚部的值,然后将其分配给 Complex
对象。下面是重载输入运算符 >>
的示例代码:
#include <iostream>
class Complex {
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
// ...
friend std::istream& operator>>(std::istream& is, Complex& c) {
std::cout << "Enter real part: ";
is >> c.real;
std::cout << "Enter imaginary part: ";
is >> c.imag;
return is;
}
private:
double real;
double imag;
};
我们同样使用 friend
关键字将重载函数声明为友元函数,以便访问 Complex
类的私有成员变量。在重载函数中,我们提示用户输入实部和虚部的值,并将其分别读取到 Complex
对象的成员变量中。
通过重载 <<
和 >>
运算符,我们可以像使用内置类型一样使用自定义类型的对象进行输入和输出。
总结
运算符重载是 C++ 的一个强大特性,它使我们可以扩展运算符的行为,使其适用于自定义类型。通过明智而一致地使用运算符重载,我们可以编写出更清晰、更易读的代码。