常用运算符:C/C++运算符优先级
operator()
operator()
在 C++ 中有两个主要作用:
重载 ()操作符 (Overloading)
-
函数对象(Functors): 当一个类重载了
()
操作符时,它的对象可以像函数一样被调用。这样的类对象被称为函数对象。 -
灵活性: 与普通函数相比,函数对象更为灵活,代码也更加优雅。
-
状态共享: 函数对象可以有自己的状态变量,使得在多次调用过程中可以共享这些状态。
-
独特的类型: 函数对象有其特有的类型,可以通过传递相应的类型作为参数来实例化特定的模块,例如带参数的函数形参。
|
实现对象类型转换 (Casting)
-
在 C++ 中,可以通过
operator Type()
的形式定义类型转换函数,从而将类对象转换为指定的Type
类型。
|
不能重载的运算符
运算符 | 描述 | 不能重载的原因 |
---|---|---|
&& 和 ` |
` | |
?: |
条件运算符 | 固有语法,语法层面与控制流结构绑定,重载会影响逻辑清晰度和代码可读性。 |
, |
逗号运算符 | 重载后无法保证左侧表达式先于右侧表达式求值,破坏顺序求值语义。 |
:: |
作用域解析运算符 | 直接影响作用域解析机制,重载会破坏语言的基本结构,影响编译器解析符号的能力。 |
. |
成员访问运算符 | 影响对象的成员访问机制,破坏类的封装性和对象模型。 |
.* |
成员指针访问运算符 | 重载会复杂化成员指针解析,影响代码的可读性和一致性。 |
typeid , const_cast , dynamic_cast , reinterpret_cast , static_cast |
类型转换运算符 | 重载会破坏类型安全性,导致代码不稳定。 |
sizeof |
获取类型或对象大小 | 与内存布局和编译器行为直接相关,重载会导致内存管理和优化过程复杂化。 |
alignof |
获取类型的对齐要求 | 与内存布局相关,不能重载。 |
typeid |
获取类型信息 | 属于RTTI机制的一部分,重载会影响类型信息获取,破坏RTTI机制。 |
new , delete , new[] , delete[] |
内存分配和释放 | 关键字 new 和 delete 的行为是固定的,尽管可以重载 operator new 和 operator delete ,但不能重载关键字本身的行为。 |
运算符重载
-
保持运算符语义:在重载运算符时,应保留该运算符作用于基本数据类型时的特性和语义。例如:
+
和+=
:应体现加法和复合赋值操作的语义。++
和--
:区分前置和后置操作符,前置返回自增/自减后的值,后置返回自增/自减前的值。
-
运算符重载形式:运算符重载可以作为类的成员函数或友元函数来实现:
- 成员函数:适用于操作数个数减少的情况。形参个数等于操作数个数减1(
++
和--
的后置版本除外)。 - 友元函数:适用于需要访问类的私有成员的情况。形参个数等于操作数个数(
++
和--
的后置版本除外)。
- 成员函数:适用于操作数个数减少的情况。形参个数等于操作数个数减1(
重载成员函数
-
改变对象状态:通常涉及改变对象内部状态的运算符(如自增、自减、赋值)应该定义为成员函数。这是因为成员函数可以直接访问对象的私有成员并修改其状态。
-
必须定义为成员的运算符:
赋值运算符 (
=
)、下标运算符 ([]
)、函数调用运算符 (()
)、成员访问箭头运算符 (->
) 必须定义为类的成员函数,否则会出现编译错误。class MyClass {
public:
int value;
// 构造函数
MyClass(int v) : value(v) {}
// 重载 += 运算符(成员函数)
MyClass& operator+=(const MyClass& rhs) {
value += rhs.value;
return *this;
}
// 重载前置 ++ 运算符(成员函数)
MyClass& operator++() {
++value;
return *this;
}
// 重载后置 ++ 运算符(成员函数)
MyClass operator++(int) {
MyClass temp = *this;
++value;
return temp;
}
};
重载友元函数
-
访问私有成员:如果需要在类外访问对象的私有成员,可以将运算符重载为友元函数。
-
避免对象调用的依赖:如果希望运算符在不依赖对象调用的情况下被使用,如
a + b
,友元函数是更好的选择。 -
类型兼容:如果运算符需要处理不同类型的操作数,如
int + class
的形式,则必须将运算符定义为全局的友元函数。class Complex {
public:
Complex(double r, double i) : real(r), imag(i) {}
// 友元函数重载 +
friend Complex operator+(const Complex& lhs, const Complex& rhs);
friend Complex operator+(double lhs, const Complex& rhs);
private:
double real;
double imag;
};
Complex operator+(const Complex& lhs, const Complex& rhs) {
return Complex(lhs.real + rhs.real, lhs.imag + rhs.imag);
}
Complex operator+(double lhs, const Complex& rhs) {
return Complex(lhs + rhs.real, rhs.imag);
}
指导原则
-
必须定义为成员的运算符:
- 赋值运算符 (
=
)、下标运算符 ([]
)、函数调用运算符 (()
)、成员访问箭头运算符 (->
) 必须定义为类的成员函数。
- 赋值运算符 (
-
通常定义为成员的运算符:
- 改变对象状态的运算符,如自增 (
++
)、自减 (--
)、解引用 (*
),通常定义为成员函数。
- 改变对象状态的运算符,如自增 (
-
通常定义为友元的运算符:
- 对称运算符,如算术运算符(
+
、-
等)、相等运算符(==
、!=
)、关系运算符(<
、>
等)更适合定义为友元函数,因为它们通常涉及两个不同类型的操作数。 - 输入输出运算符 (
<<
和>>
) 也应定义为友元函数,以便处理类与流对象的交互。
class Complex {
public:
Complex(double r, double i) : real(r), imag(i) {}
// 友元函数重载 <<
friend std::ostream& operator<<(std::ostream& os, const Complex& c);
private:
double real;
double imag;
};
std::ostream& operator<<(std::ostream& os, const Complex& c) {
os << "(" << c.real << ", " << c.imag << ")";
return os;
} - 对称运算符,如算术运算符(
class MyClass { |