在 C++ 中,运算符重载允许你为自定义的类类型定义特定的运算符行为。这样,你就可以使用运算符(如 +
、-
、*
等)来操作自定义类型的对象,使得代码更加简洁、可读。
1. 运算符重载的基本语法
运算符重载的基本语法形式如下:
return_type operator符号(参数列表)
{
// 操作符重载逻辑
}
return_type
:返回类型,通常是运算结果的类型。operator符号
:需要重载的运算符,例如+
、-
、*
。参数列表
:可以是一个或多个参数,取决于运算符的性质。
2. 运算符重载的类型
C++ 支持多种运算符的重载,包括:
- 算术运算符(
+
,-
,*
,/
,%
,++
,--
) - 关系运算符(
==
,!=
,<
,>
,<=
,>=
) - 逻辑运算符(
&&
,||
,!
) - 位运算符(
&
,|
,^
,<<
,>>
) - 赋值运算符(
=
,+=
,-=
,*=
,/=
,%=
,&=
,|=
,^=
) - 流运算符(
<<
,>>
) - 下标运算符(
[]
) - 函数调用运算符(
()
) - 类型转换运算符(
explicit operator
)
3. 运算符重载的示例
3.1 算术运算符重载
假设我们有一个 Complex
类,表示复数,我们想要重载 +
运算符来实现复数的加法:
#include <iostream>
class Complex {
private:
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// 重载 + 运算符
Complex operator+(const Complex& other) {
return Complex(real + other.real, imag + other.imag);
}
void print() const {
std::cout << real << " + " << imag << "i" << std::endl;
}
};
int main() {
Complex c1(1.0, 2.0);
Complex c2(2.5, 3.5);
Complex c3 = c1 + c2; // 使用重载的 + 运算符
c3.print(); // 输出 3.5 + 5.5i
return 0;
}
3.2 关系运算符重载
我们可以重载 ==
运算符来判断两个 Complex
对象是否相等:
#include <iostream>
class Complex {
private:
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// 重载 == 运算符
bool operator==(const Complex& other) const {
return (real == other.real) && (imag == other.imag);
}
void print() const {
std::cout << real << " + " << imag << "i" << std::endl;
}
};
int main() {
Complex c1(1.0, 2.0);
Complex c2(1.0, 2.0);
Complex c3(2.0, 3.0);
std::cout << (c1 == c2 ? "Equal" : "Not equal") << std::endl; // Equal
std::cout << (c1 == c3 ? "Equal" : "Not equal") << std::endl; // Not equal
return 0;
}
3.3 赋值运算符重载
赋值运算符重载用于正确处理对象的赋值操作,防止浅拷贝和内存泄漏。
#include <iostream>
#include <cstring>
class String {
private:
char* str;
public:
String(const char* s = "") {
str = new char[strlen(s) + 1];
strcpy(str, s);
}
// 重载赋值运算符
String& operator=(const String& other) {
if (this == &other) // 防止自赋值
return *this;
delete[] str; // 释放原有的内存
str = new char[strlen(other.str) + 1];
strcpy(str, other.str);
return *this;
}
void print() const {
std::cout << str << std::endl;
}
~String() {
delete[] str;
}
};
int main() {
String s1("Hello");
String s2;
s2 = s1; // 使用重载的赋值运算符
s2.print(); // 输出 Hello
return 0;
}
3.4 下标运算符重载
我们可以重载 []
运算符来访问类中的数据:
#include <iostream>
class Array {
private:
int* arr;
int size;
public:
Array(int s) : size(s) {
arr = new int[size];
}
// 重载 [] 运算符
int& operator[](int index) {
return arr[index];
}
void print() const {
for (int i = 0; i < size; i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
}
~Array() {
delete[] arr;
}
};
int main() {
Array arr(5);
arr[0] = 10; // 使用重载的 [] 运算符
arr[1] = 20;
arr.print(); // 输出 10 20 0 0 0
return 0;
}
3.5 输入输出流运算符重载
输入输出流运算符重载允许自定义类的对象与标准输入输出流进行交互。
#include <iostream>
class Complex {
private:
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// 重载 << 运算符
friend std::ostream& operator<<(std::ostream& out, const Complex& c) {
out << c.real << " + " << c.imag << "i";
return out;
}
// 重载 >> 运算符
friend std::istream& operator>>(std::istream& in, Complex& c) {
in >> c.real >> c.imag;
return in;
}
};
int main() {
Complex c1;
std::cout << "Enter a complex number (real imag): ";
std::cin >> c1; // 使用重载的 >> 运算符
std::cout << "You entered: " << c1 << std::endl; // 使用重载的 << 运算符
return 0;
}
4. 注意事项
- 运算符重载的限制:
- 不能重载某些运算符,如
::
、sizeof
、.
、?:
等。 - 运算符重载不能改变运算符的优先级或结合性。
- 不能重载某些运算符,如
- 运算符重载的友元函数:一些运算符(如流插入
<<
和流提取>>
)通常会被定义为友元函数,因为它们需要访问类的私有成员。 - 避免滥用运算符重载:尽管运算符重载可以提高代码的简洁性和可读性,但滥用它可能导致代码难以理解和维护。只有在运算符行为直观时才应该进行重载。
总结
运算符重载是 C++ 中的一项强大功能,它可以使自定义类型的对象像基本数据类型一样使用常见的运算符,从而提高代码的可读性和简洁性。理解和正确使用运算符重载,可以帮助你编写更符合直觉的代码。
发表回复