C++类和对象运算符重载

发布时间:2026/10/2 19:18:01
C++类和对象运算符重载 运算符重载是 C 面向对象编程中一项非常实用的特性它允许我们为自定义类型如日期类重新定义运算符的行为使代码表达更自然、更贴近直觉。本文将以日期类为例系统讲解运算符重载的核心概念与适用场景并重点演示 、、、-、- 等常用运算符的重载实现同时剖析其中容易踩坑的常见问题帮助读者真正掌握这一技巧。目录一、基本定义二、重载实例三、常见问题与总结摘要本文以日期类为例系统讲解 C 运算符重载的核心概念与适用场景。文章首先介绍运算符重载的基本定义与函数特性随后重点演示 、、、-、- 等常用运算符的重载实现并深入剖析成员函数参数匹配、const 引用绑定右值、临时对象生命周期等常见问题帮助读者掌握运算符重载的实战技巧。运算符重载是 C 面向对象编程中一项非常实用的特性它允许我们为自定义类型如日期类重新定义运算符的行为使代码表达更自然、更贴近直觉。本文将以日期类为例系统讲解运算符重载的核心概念与适用场景并重点演示 、、、-、- 等常用运算符的重载实现同时剖析其中容易踩坑的常见问题帮助读者真正掌握这一技巧。目录一、基本定义二、重载实例一、基本定义当运算符被用于类类型的对象时C语言允许我们通过运算符重载的形式指定新的含义。C规定类类型对象使用运算符时必须转换成调用对应运算符重载若没有对应的运算符重载则会编译报错。运算符重载是具有特殊名字的函数它的名字是由operator和后面要定义的运算符共同构成。和其他函数一样它也具有其返回类型和参数列表以及函数体。重载运算符函数的参数个数和该运算符作用的运算对象数量一样多。一元运算符有一个参数二元运算符有两个参数二元运算符的左侧运算对象传给第一个参数右侧运算对象传给第二个参数。如果一个重载运算符函数是成员函数则它的第一个运算对象默认传给隐式的this指针因此运算符重载作为成员函数时参数比运算对象少一个。这里以日期类对象的运算符重载为例class Date { int _year; int _month; int _day; //构造 public: Date(int year 1, int month 1, int date 1){ _yearyear; _monthmonth; _dayday; } //拷贝构造 Date(const Date d){ _year year; _month month; _day date; } void Print() { cout _year / _month / _day endl; }拷贝构造函数最好参数加const因为C中有一条规则非 const 的左值引用不能绑定到右值。后文会有所体现二、重载实例1、重载当我们想要判断两个日期是否相等时可以通过重载运算符进行实现。图中可见编译器报错。这是因为Date类成员变量均为private不能在类外被访问。我们有如下解决方法1、把成员变量设置为公有public不推荐2、类中提供访问成员变量的接口比较麻烦3、设置为友元4、把运算符重载函数移入类中成为成员函数。我们采用第四种方法解决图中仍然报错报错显示参数不匹配这是因为只能有两个参数但成员函数默认有一个this指针导致参数不匹配。解决方法如下提醒由于操作符的优先级高于操作符因此将d1d2打上括号避免冲突。否则编译器将会报错2、和的重载当需要知道某年某月某日之后day天的日期时我们可以使用操作符或重载。对于日期我们需要知道某年是否是闰年某月有多少天因此我们需要两个函数来帮助实现判断闰年和每月天数。//判断某年是否是闰年 bool IsLeapYear(int year) { if (year % 400 0) { return true; } if (year % 4 0 year % 100 ! 0) { return true; } return false; }闰年能被400整除的是闰年能被4整除但不能被100整除的是闰年。//获取某年某月的天数 int GetMonthDay(int year, int month) { int MonthDay[13] { 0,31,28,31,30,31,30,31,31,30,31,30,31 }; if (IsLeapYear(year) month 2) { return MonthDay[2] 1; } else { return MonthDay[month]; } }平年与闰年的差别在2月平年2月28年闰年29天其他月份相同。和的区别在于原始的Date类对象是否改变不改变原始的Date类对象返回的是一个临时变量。而返回的是原本的Date类对象。1重载Date Date::operator (int day) { assert(day0); Date tmp *this; // 拷贝原对象操作tmp不动原来的this tmp._day day; while (tmp._day GetMonthDay(tmp._year, tmp._month)) { tmp._day - GetMonthDay(tmp._year, tmp._month); tmp._month; if (tmp._month 13) { tmp._month 1; tmp._year; } } return tmp; }在函数内定义一个临时变量拷贝*this的全部数据确保后续操作只针对tmp。while的循环跳出条件当tmp.day当前月份的最大天数时循环终止。此时的年月日即为day天之后的年月日。返回的tmp不能返回引用因为tmp是操作符重载函数内的一个临时变量函数运行完则销毁内部资源强制返回的引用是野引用。当在main中进行如下操作时int main() { Date d1(2022, 4, 23); Date d2 d1 100; return 0; }d1100为右值临时对象、字面量通常没有名字d2为左值有名字、有地址、可被修改。赋值操作调用了拷贝构造函数如果拷贝构造函数的引用参数没有被const修饰Date(Date d);编译器会报错。应该修改为Date(const Date d);根本原因是语义安全防止修改一个即将消失的对象假设允许这样Date r d2 100; // 假设合法 r._day 99; // 修改这个临时对象d2 100返回的临时对象在整个表达式结束后就会被销毁。你通过r修改它改的是一个命不久矣的对象改完马上没了毫无意义而且极易让人误以为改的是d2。const T为什么可以因为const T承诺不修改这个对象。既然不修改绑定一个临时对象就没危险。而且 C 还规定当const T绑定到右值时会延长这个临时对象的生命周期直到该引用变量销毁。2重载与重载大同小异区别在于返回的是原本的Date对象。代码如下Date Date::operator(int day) { _day day; while (_day GetMonthDay(_year, _month)) { _day - GetMonthDay(_year,_month); _month; if (_month 13) { _month 1; _year; } } return *this; }由于this指针可以显式调用所以直接返回this指针的解引用。3、-和-重载当需要知道当前日期往前day天的日期时使用-或-重载1-重载Date Date::operator - (int day) { Date tmp *this; // 拷贝原对象操作tmp不动原来的this tmp._day - day; while (tmp._day0) { if (tmp._month 1) { tmp._month 12; tmp._year--; } else { tmp._month--; } tmp._day GetMonthDay(tmp._year, tmp._month); } return tmp; }2-重载Date Date::operator-(int day) { _day - day; while (_day 0) { if (_month 1) { _month 12; _year--; } else { _month--; } _day GetMonthDay(_year, _month); } return *this; }同上二者区别在于返回值-重载返回临时变量-重载返回this指针的解引用。总结与常见坑运算符重载是 C 面向对象编程中提升代码可读性的重要手段但使用过程中也容易踩坑。下面总结几个关键要点和常见错误帮助读者避坑。关键要点成员函数参数个数作为成员函数重载时第一个运算对象通过隐式的 this 指针传入因此参数个数比运算对象少一个。例如二元运算符 作为成员函数时只需一个显式参数。const 引用绑定右值拷贝构造函数等参数应使用 const 引用如Date(const Date d)因为非 const 的左值引用不能绑定到右值否则编译器会报错。临时对象生命周期 重载返回的临时对象在表达式结束后即被销毁不能返回其引用否则会产生野引用。const 引用可以延长临时对象的生命周期。 与 的区别 不改变原对象返回临时变量 修改原对象返回 this 指针的解引用。常见错误示例及修正错误一拷贝构造函数参数缺少 constDate(Date d); // 错误非 const 左值引用不能绑定右值修正Date(const Date d); // 正确const 引用可绑定右值错误二 重载返回局部变量的引用Date operator(int day) { // 错误返回局部临时变量的引用 Date tmp *this; // ... return tmp; // tmp 在函数结束后销毁返回的是野引用 }修正按值返回临时对象。Date operator(int day) { // 正确按值返回 Date tmp *this; // ... return tmp; }错误三 重载时参数个数不匹配bool operator(const Date d1, const Date d2); // 错误作为成员函数时参数多了一个修正作为成员函数时第一个运算对象由 this 提供只需一个显式参数。bool operator(const Date d) const; // 正确this 为左操作数d 为右操作数错误四 重载返回临时对象而非引用Date operator(int day) { // 错误 应返回引用以支持链式调用 _day day; // ... return *this; // 返回副本而非原对象 }修正返回 this 指针的解引用。Date operator(int day) { // 正确返回引用 _day day; // ... return *this; }