C++ 中运算符重载的核心机制
为何需要运算符重载
C++ 内置的运算符仅支持基础数据类型(如 int、double、char 等),无法直接作用于自定义类对象。然而在实际开发中,我们常希望对自定义类型(如复数、矩阵、时间等)使用类似 +、- 的操作,使代码更直观、简洁。
例如,两个复数相加本应是数学上的自然操作,但在原始 C++ 中无法写成 c1 + c2。通过运算符重载,我们可以赋予用户自定义类型与内置运算符相同的语义。
重载方式:成员函数与普通函数
运算符重载本质上是函数重载,可定义为类的成员函数或全局函数。其基本语法如下:
返回类型 operator 运算符(参数列表)
{
// 实现逻辑
}
以下以复数类为例,展示如何重载 + 和 - 运算符:
class Complex {
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
// 重载减号作为成员函数
Complex operator-(const Complex& other) const {
return Complex(real - other.real, imag - other.imag);
}
// 声明友元函数,用于重载加号
friend Complex operator+(const Complex& a, const Complex& b);
void display() const {
std::cout << real << "," << imag << std::endl;
}
private:
double real; // 实部
double imag; // 虚部
};
// 全局函数形式的加法重载
Complex operator+(const Complex& a, const Complex& b) {
return Complex(a.real + b.real, a.imag + b.imag);
}
int main() {
Complex x(3.5, 2.1);
Complex y(1.4, 0.9);
Complex z;
z = x + y; // 等价于: z = operator+(x, y)
z.display();
z = x - y; // 等价于: z = x.operator-(y)
z.display();
return 0;
}
输出结果:
4.9,3.0
2.1,1.2
对比两种重载方式:
- 成员函数形式:运算符左侧对象隐式传入,参数数量比运算目数少一。如
x - y对应x.operator-(y)。 - 全局函数形式:所有操作数均显式传递,参数数量等于运算目数。如
x + y对应operator+(x, y)。
将 + 重载为友元函数是为了能直接访问类的私有成员(real、imag),否则会因权限限制编译失败。
参数与返回值的设计考量
分析以下两个关键设计点:
为什么参数用 const Complex&?
若使用值传递 Complex c,调用时需调用拷贝构造函数创建临时副本,造成性能开销。采用引用传递避免复制,同时加上 const 保证不修改原对象,提升效率和安全性。
为什么返回值是 Complex 而非 Complex&?
由于运算结果是一个新构造的对象(如两复数相加生成的新复数),不能返回一个指向局部变量的引用(该变量会在函数结束时销毁)。因此必须返回值类型,确保返回的是一个有效且独立的对象。
