尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

【C++】005 C++进阶实战:从.h到.cpp,手把手带你吃透运算符重载(附完整代码)

发布时间:2026/9/24 17:28:30

资讯中心
01
ARTICLE

【C++】005 C++进阶实战:从.h到.cpp,手把手带你吃透运算符重载(附完整代码)

【C++】005 C++进阶实战:从.h到.cpp,手把手带你吃透运算符重载(附完整代码)
好我们书接上回继续讲解C类和对象中的相关内容。5.2 赋值运算符重载赋值运算符有一个默认成员函数用于完成两个已经存在的对象直接的拷贝赋值这里要注意跟拷贝构造区分拷贝构造用于一个对象拷贝初始化给另一个要创建的对象。赋值运算符重载的特点1. 赋值运算符重载是一个运算符重载规定必须重载为成员函数。赋值运算符重载的参数建议写成const当前类类型引用否则会传值传参会有拷贝。#includeiostream using namespace std; class Date { public: Date(int year 1, int month 1, int day 1) { _year year; _month month; _day day; } Date(const Date d) { _year d._year; _month d._month; _day d._day; } void operator(const Date d) { _year d._year; _month d._month; _day d._day; } void Print() { cout _year - _month - _day endl; } private: int _year; int _month; int _day; }; int main() { Date d1(2026, 9, 18); Date d2(d1); Date d3(2026, 9, 18); d1 d3; //属于赋值运算符重载 Date d4 d1;//属于拷贝构造 return 0; }2. 有返回值且建议写成当前类类型引用引用返回可以提高效率有返回值目的是为了支持连续赋值场景。Date operator(const Date d) { //此处是为了防止自己的值赋给自己 if(this!d) { _year d._year; _month d._month; _day d._day; } return *this; } }; int main() { Date d1(2026, 9, 18); Date d2(d1); Date d3(2026, 9, 18); d1 d3; Date d4 d1; Date d5(2026, 10, 1); //连续赋值 d1 d3 d5; d1.Print(); return 0; }3. 没有显式实现时编译器会自动生成一个默认运算符重载默认赋值运算符重载行为跟默认拷贝构造函数类似对内置类型成员变量会完成值拷贝/浅拷贝一个字节一个字节的拷贝对自定义类型成员变量会调用它的赋值重载函数。4. 像Date这样的类成员变量全是内置类型且没有指向什么资源 编译器自动生成的赋值运算符重载就可以完成需要的拷贝所以不需要我们显式实现赋值运算符重载。像Stack这样的类虽然也都是内置类型但是_a指向了资源编译器自动生成的赋值运算符重载完成的值拷贝/浅拷贝不符合我们的需求所以需要我们自己实现深拷贝对指向的资源也进行拷贝像MyQueue这样的类型内部主要是自定义类型Stack成员编译器自动生成的赋值运算符重载会调用Stack的赋值运算符重载也不需要我们显式实现MyQueue的赋值运算符重载。这里还有一个小技巧如果一个类显式实现了析构并释放资源那么它就需要显式写赋值运算符重载否则就不需要。六. 综合练习我们现在借助日期类来实现运算符的重载本次练习我们以下面几个运算符的重载为例它们分别是、、前置、后置、-、-、前置--、后置--等等。6.1 .h文件#pragma once #includeiostream #includeassert.h using namespace std; class Date { public: Date(int year 1900, int month 1, int day 1); void Print(); int GetMonthDay(int year, int month) { assert(month 0 month 13); static int monthDayArray[13] { -1,31,28,31,30,31,30,31,31,30,31,30,31 }; if (month 2 (year % 4 0 year % 100 ! 0) || (year % 400 0)) { return 29; } else { return monthDayArray[month]; } } bool CheckDate() { if (_month 1 || _month12) return false; if (_day1 || _dayGetMonthDay(_year, _month)) return false; return true; } bool operator(const Date d); bool operator(const Date d); bool operator(const Date d); bool operator(const Date d); bool operator(const Date d); bool operator!(const Date d); //d1天数 Date operator (int day); Date operator(int day); //d1-天数 Date operator-(int day); Date operator-(int day); //d1-d2 int operator-(const Date d); Date operator(); //d1 - d1.operator(0) //为了区分构成重载给后置强行增加一个int形参 //这里不需要写形参名因为接收值是多少不重要也不需要用 //这个参数仅仅是为了跟前置构成重载区分 Date operator(int); //前置 Date operator--(); //后置 Date operator--(int); //友元函数的声明 friend ostream operator(ostream out, const Date d); friend istream operator(istream in, Date d); private: int _year; int _month; int _day; }; // ostream operator(ostream out, const Date d); istream operator(istream in, Date d);6.2 .cpp文件//综合练习 #includelesson3.h Date::Date(int year, int month, int day )//注意缺省参数声明和定义不能同时给 { _year year; _month month; _day day; if (!CheckDate()) { cout 非法日期 *this; } } void Date::Print() { cout _year - _month - _dayendl; } //d1100 Date Date::operator(int day) { if (day 0) { return *this - -day; } _day day; while (_day GetMonthDay(_year,_month)) { _day - GetMonthDay(_year, _month); _month; if (_month 13) { _year; _month 1; } } //上述代码可以替换成*this*thisday; return *this; } //d1100 Date Date::operator(int day) { Date tmp(*this);//拷贝构造*this是d1,d1不能改变 tmp._day day; while (tmp._day GetMonthDay(_year, _month)) { tmp._day - GetMonthDay(_year, _month); _month; if (tmp._month 13) { tmp._year; tmp._month 1; } }//以上内容可替换成tmpday return tmp; } //d5 - d5.operator(0) Date Date::operator(int) { Date tmp(*this); *this 1; return tmp; } //d6 Date Date:: operator() { *this 1; return *this; } //- Date Date::operator-(int day) { if (day 0) { return *this -day; } _day - day; while (_day 0) { --_month; if (_month 0) { --_year; _month 12; } _day GetMonthDay(_year, _month); } return *this;//出了作用域d1还在所以用引用返回可以减少拷贝 } //- Date Date::operator-(int day) { Date tmp *this; tmp - day; return tmp; } //前置--和后置-- Date Date::operator--() { *this - 1; return *this; } Date Date::operator--(int) { Date tmp *this; *this - 1; return tmp; } bool Date::operator(const Date d) { if (_year d._year) return true; else if (_year d._year) { if (_month d._month) return true; else if (_month d._month) return _day d._day; } return false; } bool Date::operator(const Date d) { return *this d || *this d; } bool Date::operator(const Date d) { if (_year d._year) return true; else if (_year d._year) { if (_month d._month) return true; else if (_month d._month) return _day d._day; } return false; //上述代码也可以写成:return !(*thisd); } bool Date::operator(const Date d) { return !(*this d); } bool Date::operator(const Date d) { return _year d._year _month d._month _day d._day; } bool Date::operator!(const Date d) { return !(*this d); } //日期-日期 int Date::operator-(const Date d) { Date max *this; Date min d; int flag 1; if (*this d) { min *this; max d; flag -1; } int day 0; while (min ! max) { min; day; } return day * flag; } // ostream operator(ostream out,const Date d) { out d._year / d._month / d._day endl; return out; } // istream operator(istream in, Date d) { while (1) { cout 请依次输入年月日 endl; in d._year d._month d._day; if (d.CheckDate()) { break; } else { cout 输入日期非法请重新输入 endl; } } return in; } void test1() { Date d1(2025, 8, 1); Date d2 d1 100; d1.Print(); d2.Print(); Date d3(2025, 8, 1); Date d4 d3 100; d3.Print(); d4.Print(); Date d5(2025, 8, 1); Date rat1 d5; rat1.Print(); Date d6(2025, 8, 1); Date rate2 d6; rate2.Print(); //Date d7operator(100); Date d7 d1.operator(100); Date d8 d1 100; Date d9(2025, 9, 8); d9 - 50; d9.Print(); Date d10 d9 - 50; } void test2() { Date d1(2025, 9, 8); Date d2--d1; d1.Print(); d2.Print(); Date d3 d1--; d1.Print(); d3.Print(); } void test3() { Date d1(2026, 9, 21); Date d2(2026, 10, 1); cout d2 - d1endl; } void test4() { Date d1(2026, 9, 21); Date d2(2026, 10, 1); //operator(cout, d1); cin d1 d2; cout d1 d2; //虽然可以跑但是不符合可读性 /*d1.operator(cout); d1 cout;*/ } int main() { //test1(); /*test2(); test3();*/ test4(); int i 1; double d 1.1; cout i;//cout.operator(i) cout d;//cout.operator(d) return 0; }所以图片中两种代码复用方式上面的方式要优于下面的代码复用方式因为上面一次总共调用两次拷贝而下面要调用五次拷贝。所以建议让拷贝多的代码块去复用拷贝少的代码块。七. 取地址运算符重载7.1 const成员函数1. 将const修饰的成员函数称之为const成员函数const修饰成员函数放到成员函数参数列表的后面。2. const实际修饰该成员函数隐含的this指针表明在该成员函数中不能对类的任何成员进行修改。const修饰Date类的Print成员函数Print隐含的this指针由Date* const this变为const Date* const this。总结不修改成员变量的成员函数都应该加上const。优势是普通对象和const对象都可以调用const成员函数#includeiostream using namespace std; class Date { public: Date(int year 1, int month 1, int day 1) { _year year; _month month; _day day; } //const成员函数 //void Print(const Date* const this) const void Print()const //表示const修饰的是this指针,此时this指针不能改变它指向的内容也不能改变 { cout _year - _month - _day endl; } private: int _year; int _month; int _day; }; void test1() { const Date d1(2026, 9, 23); d1.Print(); Date d2(2026, 9, 23); d2.Print(); } int main() { test1(); return 0; }7.2 取地址运算符重载取地址运算符重载分为普通取地址运算符重载和const取地址运算符重载一般这两个函数编译器自动生成的就够我们用了不需要去显式实现。除非一些很特殊的场景比如我们不想让别人取到当前类对象的地址就可以自己实现一份胡乱返回一个地址。#includeiostream using namespace std; class Date { public: Date(int year 1, int month 1, int day 1) { _year year; _month month; _day day; } //const成员函数 //void Print(const Date* const this) const void Print()const //表示const修饰的是this指针,此时this指针不能改变它指向的内容也不能改变 { cout _year - _month - _day endl; } Date* operator() { return this; //return nullptr; } const Date* operator()const { return this; //return nullptr; } private: int _year; int _month; int _day; }; void test1() { const Date d1(2026, 9, 23); d1.Print(); Date d2(2026, 9, 23); d2.Print(); Date* p1 d2; const Date* p2 d1; cout p1 p2 endl; } int main() { test1(); return 0; }以上就是我们今天的内容至此类和对象中已完结~ 下一节我将讲述“类和对象下”大家敬请期待。觉得有帮助的朋友们可以用一键三连喔~互三必回有不足之处欢迎大家评论区批评指正后续内容会更加精彩
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。