当前位置: 首页 > news >正文

拷贝构造和运算符重载【C++】

一,拷贝构造函数

拷贝构造函数是C++ 中一种特殊的构造函数,其作用是用一个已经存在的同类型对象,创建并初始化一个新的对象。它的第一个参数是自身类类型的引用,且任何额外的参数都有默认值,它是 C++ 面向对象编程中管理对象复制、资源的机制。

拷贝构造的特点:

1,拷贝构造函数是构造函数的一个重载。

2,拷贝构造函数的第一个参数必须是类类型的引用,使用传值方式编译器直接报错,因为语法逻辑上会引发无穷递归调用。C++规定,自定义类型的对象,在直接的拷贝,传值传参,都要调用拷贝构造。如果使用传值传参,会发生下面无穷递归调用的情况。

3,C++规定自定义类型对象进行拷贝行为必须调用拷贝构造,所以这里自定义类型传值传参和传值返回都会调用拷贝构造完成。

4,拷贝构造函数也可以有多个参数,但是第一个参数必须是类类型对象的引用,后面的参数必须有缺省值。

5,以下是Data类的拷贝构造:

#include<iostream> using namespace std; class Data { public: Data(int year = 1, int month = 1, int day = 1) { this->_year = year; _month = month; _day = day; } void Print()const { cout << _year << "年" << _month << "月" << _day << "日" << endl; } Data(const Data& d)//拷贝构造函数 { this->_year = d._year; _month = d._month; _day = d._day; } ~Data() { _year = _month = _day = 0; } private: int _year; int _month; int _day; }; int main() { Data d1(2026, 5, 17); Data d3(d1); d3.Print(); return 0; }

那么有一个问题,Data类只需要对内置类型成员变量完成值拷贝(浅拷贝),需要我们显示写拷贝构造函数吗?是不需要的。若未显示定义拷贝构造,编译器自动生成的拷贝构造函数就会完成这个工作(浅拷贝),所以对于内置类型成员变量是不需要显示写拷贝构造的。

但是像Stack这样的类,需要有开辟的资源,就需要显示写拷贝构造,如果我们不显示写呢,编译器生成的还满足我们的需求吗?根据下面的报错,显然编译器生成的并不满足我们的需求,我们要显示写拷贝构造。

以下是我们实现的一个栈,显示写出拷贝构造函数。

#include<iostream> using namespace std; typedef int SDatatype; class Stack { public: Stack(int n = 5) { this->_arr = (SDatatype*)malloc(n * sizeof(SDatatype)); if (_arr == NULL) { perror("malloc fail!"); exit(1); } _top = 0; _capacity = n; } void SPush(SDatatype x) { if (_top == _capacity) { cout << "空间已满" << endl; exit(1); } _arr[_top++] = x; } void SPop() { if (_top == 0) { cout << "栈内无元素" << endl; exit(1); } _top--; } SDatatype STop() { if (_top == 0) { cout << "栈内无元素" << endl; exit(1); } return _arr[_top - 1]; } Stack(const Stack& st)//拷贝构造函数 { this->_arr = (SDatatype*)malloc(st._capacity * sizeof(SDatatype)); if (_arr == NULL) { perror("copy malloc fail!"); exit(1); } memcpy(_arr, st._arr, sizeof(SDatatype) * st._top); _top = st._top; _capacity = st._capacity; } ~Stack() { if (_arr) free(_arr); _arr = NULL; _top = _capacity = 0; } private: SDatatype* _arr; int _top; int _capacity; }; int main() { Stack st1; st1.SPush(3); st1.SPush(2); st1.SPush(6); cout << st1.STop() << endl; Stack st2(st1); cout << st2.STop() << endl; return 0; }

我们如何判断什么时候要显示写拷贝构造呢?这里有个技巧,如果一个类显示实现了析构并释放资源,那么他就需要显示写拷贝构造,否则就不需要。

二,运算符重载

学习了运算符重载,就可以丰富我们的Data类了,比如日期减日期,就是相差的天数;日期加(减)天数,就是离这个日期多少天后(前)的日期。

运算符重载特点:

1,当运算符被用于类类型的对象时,C++语言允许我们通过运算符重载的形式指定新的含义。C++规定类类型对象使用运算符时,必须转换成调用运算符重载,若没有,则会编译报错。

2,运算符重载的名字是由operator和后面要定义的运算符共同构成,和其他函数一样,它也具有其返回类型和参数列表及函数体。

3,重载运算符函数的参数个数和该运算符作⽤的运算对象数量⼀样多。⼀元运算符有⼀个参数,⼆元运算符有两个参数,⼆元运算符的左侧运算对象传给第⼀个参数,右侧运算对象对象传给第二个参数。

4,如果⼀个重载运算符函数是成员函数,则它的第⼀个运算对象默认传给隐式的this指针,因此运算符重载作为成员函数时,参数⽐运算对象少⼀个。

5,运算符重载以后,其优先级和结合性与对应的内置类型运算符保持⼀致。

6,不能通过连接语法中没有的符号来创建新的操作符:⽐如operator@。

7,.* :: sizeof ? : .注意以上5个运算符不能重载。

8,重载操作符至少有⼀个类类型参数,不能通过运算符重载改变内置类型对象的含义,如: int operator+(int x, int y)

9,⼀个类需要重载哪些运算符,是看哪些运算符重载后有意义,⽐如Date类重载operator-就有意义,但是重载operator/就没有意义。

10,重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,无法很好的区分。C++规定,后置++重载时,增加⼀个int形参,跟前置++构成函数重载,方便区分。

11,重载<<和>>时,需要重载为全局函数,因为重载为成员函数,this指针默认抢占了第⼀个形参位置,第⼀个形参位置是左侧运算对象,调用时就变成了 对象<<cout,不符合使用习惯和可读性。重载为全局函数把ostream/istream放到第⼀个形参位置就可以了,第二个形参位置当类类型对象。

#include<iostream> using namespace std; class Data { public: Data(int year = 1, int month = 1, int day = 1) { this->_year = year; _month = month; _day = day; } //获取当前月天数 int GetmonthDay(int year, int month); void Print()const { cout << _year << "年" << _month << "月" << _day << "日" << endl; } //两个日期比较 bool operator==(const Data& x2)const { return this->_year == x2._year && _month == x2._month && _day == x2._day; } //日期加天数 Data operator+(int day); //日期加等天数 Data& operator+=(int day); //日期减天数 Data operator-(int day); //日期减等天数 Data& operator-=(int day); Data(const Data& d)//拷贝构造,Data类可以不用写 { this->_year = d._year; _month = d._month; _day = d._day; } ~Data()//析构函数,Data类可以不用写 { _year = _month = _day = 0; } private: int _year; int _month; int _day; }; //日期加天数 Data Data::operator+(int day) { Data 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 > 12) { tmp._year++; tmp._month = 1; } } return tmp; } //日期加等天数 Data& Data::operator+=(int day) { this->_day += day; while (_day > GetmonthDay(_year, _month)) { _day -= GetmonthDay(_year, _month); _month++; if (_month > 12) { _year++; _month = 1; } } return *this; } //日期减天数 Data Data::operator-(int day) { Data tmp = *this; tmp._day -= day; while (tmp._day <= 0) { tmp._month--; if (tmp._month == 0) { tmp._year--; tmp._month = 12; } tmp._day += GetmonthDay(tmp._year, tmp._month); } return tmp; } //日期减等天数 Data& Data::operator-=(int day) { this->_day -= day; while (_day <= 0) { _month--; if (_month == 0) { _year--; _month = 12; } _day += GetmonthDay(_year, _month); } return *this; } //获取当前月天数 int Data::GetmonthDay(int year, int month) { static int Month[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 Month[month]; } int main() { Data d1(2026, 5, 17); Data d2(2026, 5, 20); Data d3(d1); //两个日期比较 cout << "两个日期比较" << endl; cout << "d2==d1?" << " " << (d2 == d1) << endl; //日期加天数 cout << "日期加天数" << endl; d3.Print(); d3 = d1 + 100; d3.Print(); d1.Print(); //日期加等天数 cout << "日期加等天数" << endl; d1.Print(); d1 += 100; d1.Print(); //日期减天数 cout << "日期减天数" << endl; Data d4(d2); d4.Print(); d4 = d2 - 1000; d4.Print(); d2.Print(); //日期减等天数 cout << "日期减等天数" << endl; d2 -= 1000; d2.Print(); return 0; }

以上代码新加了运算符重载。

http://www.jsqmd.com/news/859973/

相关文章:

  • 开发AI应用时如何借助Taotoken模型广场进行选型
  • OpCore-Simplify:10分钟搞定黑苹果配置,告别3天手动调试的智能神器
  • PowerBI主题模板完整指南:35个JSON模板快速打造专业报表
  • 别瞎写线程!一文搞懂 Java 线程 5 种创建方法
  • Taotoken官方折扣活动如何切实降低模型调用成本
  • 初创公司如何借助Taotoken快速原型验证多个AI模型能力
  • SQL错误注入攻防实战
  • 2026年Q2中国市政管道短管置换优质厂家首选推荐:合肥玉通管道工程有限公司 - 安互工业信息
  • 应对高并发场景Taotoken的容灾与路由策略如何保障服务稳定
  • 告别手忙脚乱找字幕:Jellyfin智能字幕插件MaxSubtitle完全指南
  • 【Midjourney布料质感模拟终极指南】:20年CG专家亲授7大材质参数调优公式,92%用户忽略的Gamma映射陷阱曝光
  • 飞控延迟 10 毫秒就炸机、多舵机不同步晃得厉害?EtherCAT 工控机如何实现无人机微秒级精准控制
  • 专业干货:低查重AI教材编写工具,助力教材创作新高度!
  • 2026长沙全域奢侈品回收攻略:多网点布局上门变现更省心 - 诚鑫名品
  • 每天看800份简历的HR真的要失业了吗?AI简历筛选如何解决招聘痛点?
  • 初创团队如何利用Taotoken的Token Plan实现AI成本精细化管理
  • HSTracker:macOS炉石传说数据分析工具终极使用指南
  • 英伟达816亿营收+国产2000亿参数图像模型:AI军备赛再升级
  • 企业 SSL 证书审核难不难?怕麻烦就选速安信!
  • Taotoken模型广场如何帮助开发者选择合适的模型进行调试
  • 专业级多框架可视化解决方案:Viser.js 技术深度解析
  • 将Hermes Agent对接至Taotoken的自定义提供商配置详解
  • HS2-HF_Patch终极增强补丁:5分钟解锁Honey Select 2完整创作生态
  • 数字孪生 · 零基础4周速成学习计划(书籍+实操+项目落地)
  • 明日深圳文博会!BOSMA博冠与您相约
  • 智能音频切片工具终极指南:告别手动剪辑的烦恼
  • 2026年Q2中国污水池清理优质服务商首选推荐:合肥玉通管道工程有限公司 - 安互工业信息
  • 韦斯实验——换气式精密高温烤箱:半导体制造的“隐形工艺大师”
  • 从资源嗅探到流媒体处理:猫抓Cat-Catch浏览器扩展的技术架构演进之路
  • 百度文库纯净打印终极指南:3分钟解锁文档自由保存的完整方案