引言
C++ 提供了运算符重载这一特性,允许程序员为自定义类型(如类和结构体)定义运算符的行为。
通过运算符重载,可以使自定义类型对象像内置类型一样使用运算符,从而提高代码的可读性和易用性。
本文将详细介绍 C++ 中运算符重载的概念、语法、规则、注意事项以及实际应用。
目录
引言
?运算符重载的概念
?运算符重载的语法
?可重载的运算符
?运算符重载的规则
?运算符重载的实现
?注意事项
?实际应用
示例代码
运算符重载的应用项目:日期类实现
结语
?运算符重载的概念
运算符重载是指为类(或结构体)的特定运算符提供自定义实现,使其能够作用于类的对象。重载的运算符可以保持其原有的语义,也可以定义新的语义。
C++规 定类类型对象使⽤运算符时,必须转换成调⽤对应运算符重载,若没有对应的运算符重载,则会编译报错。
?运算符重载的语法
运算符重载通过成员函数或友元函数来实现。运算符重载是具有特殊名字的函数,他的名字是由operator和后⾯要定义的运算符共同构成。和其他 函数⼀样,它也具有其返回类型和参数列表以及函数体。如果⼀个重载运算符函数是成员函数,则它的第⼀个运算对象默认传给隐式的this指针,因此运算 符重载作为成员函数时,参数比运算对象少⼀个成员函数形式:
class MyClass { public: MyClass operator+(const MyClass& other) const; // 重载加法运算符 // ... 其他成员 ... };
友元函数形式: class MyClass { public: friend MyClass operator+(const MyClass& lhs, const MyClass& rhs); // 声明友元函数 // ... 其他成员 ... }; // 类外部定义友元函数 MyClass operator+(const MyClass& lhs, const MyClass& rhs) { // 实现加法运算 }
?可重载的运算符
C++ 允许重载几乎所有的运算符,但有几个运算符不能重载: .
.*
::
?:
sizeof
和 typeid
。这些运算符与对象的成员访问、类型信息获取等底层操作紧密相关,因此不允许重载。
?运算符重载的规则
不能改变运算符的优先级和结合性:重载的运算符仍然保持其原有的优先级和结合性。不能改变运算符的操作数个数:例如,不能将一元运算符重载为二元运算符,反之亦然。重载的运算符不能是新的类型:重载的运算符必须是 C++ 中已定义的运算符。成员运算符函数不能有默认参数:重载的运算符函数不能有默认参数。?运算符重载的实现
成员函数形式:当运算符重载为成员函数时,左侧操作数必须是该类的一个对象(或引用),而右侧操作数可以是任意类型(包括内置类型和该类类型)。友元函数形式:当运算符重载为友元函数时,两个操作数可以是任意类型(包括内置类型和该类类型),这提供了更大的灵活性。?注意事项
避免不必要的重载:只有当运算符的默认行为不适用于自定义类型时,才考虑重载。保持语义一致性:重载的运算符应尽可能保持其原有的语义,以避免混淆。注意异常安全性:在重载运算符时,要考虑到异常安全性,确保在异常发生时不会泄露资源或破坏对象状态。实用性:⼀个类需要重载哪些运算符,是看哪些运算符重载后有意义前置++与后置++:重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,无法很好的区分。 C++规定,后置++重载时,增加⼀个int形参,跟前置++构成函数重载,方便区分重载>>和<<:需要重载为全局函数,因为重载为成员函数,this指针默认抢占了第⼀个形参位 置,第⼀个形参位置是左侧运算对象,调⽤时就变成了对象<<cout,不符合语法和习惯。重载为全局函数把ostream/istream放到第⼀个形参位置就可以了,第⼆个形参位置当类类型对象?实际应用
运算符重载在 C++ 中有着广泛的应用,例如:
复数类:可以重载加法、减法、乘法和除法等运算符,使复数对象能够像内置类型一样进行算术运算。点类:可以重载加法运算符来表示点的平移,重载减法运算符来表示点的距离计算等。字符串类:可以重载加法运算符来表示字符串的连接,重载比较运算符来表示字符串的大小比较等。示例代码
以下是一个简单的复数类示例,展示了如何重载加法、减法和乘法运算符:
#include <iostream> class Complex { private: double real; double imag; public: // 构造函数 Complex(double r = 0, double i = 0) : real(r), imag(i) {} // 重载加法运算符 Complex operator+(const Complex& other) const { return Complex(real + other.real, imag + other.imag); } // 重载减法运算符 Complex operator-(const Complex& other) const { return Complex(real - other.real, imag - other.imag); } // 重载乘法运算符 Complex operator*(const Complex& other) const { return Complex(real * other.real - imag * other.imag, real * other.imag + imag * other.real); } // 重载输出运算符 friend std::ostream& operator<<(std::ostream& os, const Complex& c) { os << c.real << " + " << c.imag << "i"; return os; } }; int main() { Complex c1(1, 2); Complex c2(3, 4); Complex c3 = c1 + c2; Complex c4 = c1 - c2; Complex c5 = c1 * c2; std::cout << "c1: " << c1 << std::endl; std::cout << "c2: " << c2 << std::endl; std::cout << "c1 + c2: " << c3 << std::endl; std::cout << "c1 - c2: " << c4 << std::endl; std::cout << "c1 * c2: " << c5 << std::endl; return 0; }
在这个示例中,我们定义了一个 Complex
类来表示复数,并重载了加法、减法和乘法运算符,以及输出运算符。这样,我们就可以像使用内置类型一样使用 Complex
对象进行算术运算和输出。
运算符重载的应用项目:日期类实现
详细内容参考文章,点击下方链接:
【C++指南】类和对象入门实践:日期类实现-CSDN博客
结语
运算符重载是 C++ 中的一个强大特性,它允许程序员为自定义类型定义运算符的行为。通过合理地使用运算符重载,可以使代码更加简洁、易读和高效。然而,在重载运算符时,需要遵循一定的规则和注意事项,以确保代码的正确性和安全性。