C++:运算符重载与类的赋值运算符重载函数
目录
章节知识架构
一.运算符重载
1. 运算符重载的基本概念
代码段1
2.关于运算符重载的重要语法细则
二.运算符重载在类中的使用
三.类的默认成员函数:=重载函数(赋值运算符重载)
1.自定义=重载函数
代码段2
2.编译器默认生成的=重载函数
四.前置++(--)和后置++(--)的重载
章节知识架构
一.运算符重载
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数
1. 运算符重载的基本概念
C++中定义运算符重载的关键字:operator
- 运算符重载本质上是函数,具有返回值类型,函数名字以及参数列表,其返回值类型和参数列表与普通的函数定义规则类似;
- 运算符重载函数的函数名命名规则:关键字operator + 需要重载的运算符符号(例如定义函数名operator>,表示>的运算符重载);
- 运算符重载函数的形参个数必须和被重载运算符的目数相同:单目操作符的重载函数有且只有一个形参,双目操作符的重载函数有且只有两个形参.
- 运算符重载函数必须有一个类类型参数
- 运算符重载函数首部的一般形式:返回值类型+operator运算符+(参数列表);
比如:
现在有一个记录日期的类Date,我们想比较两个日期类对象所记录的日期大小,因此设计一个运算符 '>'的重载函数。
函数返回类型定义为bool;bool为一个字节的整形,其只能为true(值1)或false(值为0)
函数名定义为: operator>
函数的形参表为:(const Date & date2 ,const Date & date2)
代码段1
#include <iostream>using std::cout; using std::cin; using std::endl;class Date 记录日期的类 { public:Date(int day = 0, int month = 0,int year = 0) Date的带参构造函数{_day = day;_month = month;_year = year;}int _day;int _month;int _year; };bool operator> (const Date& date1, const Date& date2) 将 > 运算符进行重载用于日期比较 {if (date1._year > date2._year){return true;}else if (date1._year == date2._year && date1._month > date2._month){return true;}else if (date1._year == date2._year && date1._month == date2._month && date1._day > date1._day){return true;}return false; }int main() {Date a(2021, 4, 23);Date b(2022, 1, 27);if (a > b) 用运算符重载来比较两个日期对象{cout << "Date a > Date b" << endl;}else{cout << "Date a < Date b" << endl;}return 0; }
C++编译其会根据运算符的操作数的类型来判断该运算符是否要调用重载以及调用哪种形式的重载,比如上述代码段主函数中的 a>b表达式:
2.关于运算符重载的重要语法细则
- 不能通过连接其他符号来创建新的操作符:比如operator@
- 作为类成员运算符重载函数时,其形参个数看起来比运算符目数少1,因为类成员函数的第一个参数为隐藏的this指针;关于this指针:http://t.csdn.cn/hncvq
- 赋值运算符重载(比如=,+=,-+,*=等等)只能作为类的成员函数不能重载成全局函数
- '".* " "::" "sizeof" "?:" "." 注意以上5个运算符不能重载。
二.运算符重载在类中的使用
- C++引入运算符重载是为了提高代码的可读性,允许我们构建复杂类对象之间的运算表达式。
- 运算符重载必须有一个类类型形参,因此在运算符重载函数中我们难免要访问类的成员变量
- 为了保证封装性,类的成员变量往往定义在类的私有域中。
- 所以为了保证类对象的封装性的同时可以让运算符重载函数直接访问到类的成员变量,大多数情况下我们往往把运算符重载函数定义为类的成员函数(方法)。
现在对代码段1进行优化:
把运算符重载函数定义为类的成员函数(方法)
运算符重载函数定义为类的成员函数时注意不要忽略this指针
#include <iostream>using std::cout; using std::cin; using std::endl;class Date //记录日期的类 { public:Date(int day = 0, int month = 0,int year = 0){_day = day;_month = month;_year = year;}bool operator> (const Date& date) //将 > 运算符进行重载{if (_year > date._year){return true;}else if (_year == date._year &&_month > date._month){return true;}else if (_year == date._year && _month == date._month && _day > date._day){return true;}return false;}private:int _day;int _month;int _year; };int main() {Date a(29, 4, 2020);Date b(27, 4, 2020);if (a > b){cout << "Date a > Date b" << endl;}else{cout << "Date a < Date b" << endl;}return 0; }
简单地观察一下 a>b表达式的汇编指令:
三.类的默认成员函数:=重载函数(赋值运算符重载)
类的默认成员函数中有一个赋值运算符=的重载:
如果我们没有在类中自定义一个赋值运算符=的重载,编译器会在类中自动生成一个默认的=运算符重载函数。
1.自定义=重载函数
赋值运算符(=)只能重载成类的成员函数不能重载成全局函数
- 原因:赋值运算符如果没有被我们定义,编译器会在类中(任何类中)生成一个默认的赋值运算符重载。此时若我们在类域外定义一个全局的赋值运算符重载,就会和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。
自定义=重载函数:
现在Date类中实现一个=重载函数:如果我们在类中自定义了=重载函数,编译器便不会在编译阶段自动生成其默认的赋值运算符(=)重载。
代码段2
using std::cout; using std::cin; using std::endl;class Date 记录日期的类 { public:Date(int day = 0, int month = 0,int year = 0){_day = day;_month = month;_year = year;}bool operator> (const Date& date) 将 > 运算符进行重载{if (_year > date._year){return true;}else if (_year == date._year &&_month > date._month){return true;}else if (_year == date._year && _month == date._month && _day > date._day){return true;}return false;}Date& operator=(const Date& date) 将 = 运算符进行重载{_day = date._day;_month = date._month;_year = date._year;return (*this);}private:int _day;int _month;int _year; };int main() {Date a(29, 4, 2020);Date b;Date c;c = b = a; 用=的重载完成连续赋值if (a > b){cout << "Date a > Date b" << endl;}else {cout << "Date a <= Date b" << endl;}return 0; }
可以试着观察一下代码段中c=b=a的汇编指令:
注意:=重载函数使用引用传参和引用返回而不使用值传参和值返回是为了提高代码的运行效率(值传递需要拷贝出临时的类对象)
参见:http://t.csdn.cn/Rc5aI
http://t.csdn.cn/9tLyK
2.编译器默认生成的=重载函数
编译器默认生成的=重载函数:
编译器默认生成的=运算符重载函数的功能和代码段2中自定义的=重载函数功能类似:
可以简单验证一下:
将代码段2中等号重载的代码段注释掉
using std::cout; using std::cin; using std::endl;class Date //记录日期的类 { public:Date(int day = 0, int month = 0,int year = 0){_day = day;_month = month;_year = year;}bool operator> (const Date& date) //将 > 运算符进行重载{if (_year > date._year){return true;}else if (_year == date._year &&_month > date._month){return true;}else if (_year == date._year && _month == date._month && _day > date._day){return true;}return false;}//Date& operator=(const Date& date) //将等号重载的代码段注释掉//{// if (this != &date)// {// _day = date._day;// _month = date._month;// _year = date._year;// }// return (*this);//}private:int _day;int _month;int _year; };int main() {Date a(29, 4, 2020);Date b;Date c;c = b = a;if (a > b){cout << "Date a > Date b" << endl;}else {cout << "Date a <= Date b" << endl;}return 0; }
如果,类中有类对象成员变量,该类的编译器默认生成的=重载函数中会去调用其成员类对象的赋值运算符重载。
比如:
using std::cout; using std::cin; using std::endl;class subclass //定义一个被嵌套的类 { public:subclass(int a = 100) 定义subclass的构造函数{_a = 100;}subclass& operator = (const subclass& date) 定义subclass的赋值运算符重载函数{_a = date._a;cout << "hello" << endl; 打印一下表示该函数被调用return (*this);} private:int _a; };class Date //记录日期的类 { public:Date(int day = 0, int month = 0,int year = 0,int subclass=0){_day = day;_month = month;_year = year;}//bool operator> (const Date& date) //将 > 运算符进行重载//{// if (_year > date._year)// {// return true;// }// else if (_year == date._year &&_month > date._month)// {// return true;// }// else if (_year == date._year && _month == date._month && _day > date._day)// {// return true;// }// return false;//}//Date& operator=(const Date& date) //将等号重载的代码段注释掉//{// if (this != &date)// {// _day = date._day;// _month = date._month;// _year = date._year;// }// return (*this);//}private:int _day;int _month;int _year;subclass _subdate; };int main() {Date a(29, 4, 2020,100);Date b;Date c;c = b = a;//if (a > b)//{// cout << "Date a > Date b" << endl;//}//else //{// cout << "Date a <= Date b" << endl;//}return 0; }
可以通过汇编指令来观察这个过程:
- 需要注意的是:类似于拷贝构造函数,编译器在类中默认生成的赋值运算符重载是以逐个字节进行拷贝的方式完成类对象赋值的(这种拷贝方式称为浅拷贝)。
- 因此编译器默认生成的赋值运算符重载不能用于一些申请了额外内存资源类对象之间的拷贝赋值。(比如栈对象之间的拷贝赋值)
如果栈对象之间使用编译器默认生成的=重载函数,则会出现以下情形:
所以涉及到内存资源管理的类对象之间只能使用用户自定义的=重载完成深拷贝。
四.前置++(--)和后置++(--)的重载
针对Date类,我们来实现一下表示日期自增的++重载(日期增加一天)
using std::cout; using std::cin; using std::endl;//class subclass //定义一个被嵌套的类 //{ //public: // subclass(int a = 100) //定义subclass的构造函数 // { // _a = 100; // } // subclass& operator = (const subclass& date) //定义subclass的赋值运算符重载函数 // { // _a = date._a; // cout << "hello" << endl; //打印一下表示该函数被调用 // return (*this); // } //private: // // int _a; //};class Date //记录日期的类 { public:Date(int day = 0, int month = 0, int year = 0) //Date的构造函数{_day = day;_month = month;_year = year;}//bool operator> (const Date& date) //将 > 运算符进行重载//{// if (_year > date._year)// {// return true;// }// else if (_year == date._year &&_month > date._month)// {// return true;// }// else if (_year == date._year && _month == date._month && _day > date._day)// {// return true;// }// return false;//}//Date& operator=(const Date& date) //{// if (this != &date)// {// _day = date._day;// _month = date._month;// _year = date._year;// }// return (*this);//}Date& operator++() //实现日期类的前置++{_day++;return (*this);}Date operator++(int) //实现日期类的后置++{Date tem(*this);_day++;return tem;}void Print() //类对象的日期打印函数{cout << _year << ' ' << _month << ' ' << _day << ' ' << endl;}private:int _day;int _month;int _year;};int main() {Date a(5, 4, 2020);a.Print();Date ret1(a++);ret1.Print();Date ret2(++a);ret2.Print();return 0; }
代码图解:
注意一个语法细则:
前置--和后置--的重载和++类似。
C++:运算符重载与类的赋值运算符重载函数相关推荐
- C++类的赋值运算符“=”重载,以及深拷贝和浅拷贝
C++类的赋值运算符"="重载,以及深拷贝和浅拷贝 在面向对象程序设计中,对象间的相互拷贝和赋值是经常进行的操作. 如果对象在申明的同时马上进行初始化操作,则称之为拷贝运算.例如: ...
- 派生类的赋值运算符重载【C++继承】
派生类的赋值符重载 情况分析 父类和子类都使用系统默认提供的赋值运算符重载 父类自实现赋值运算符重载,子类使用系统默认提供的赋值运算符重载. 父类使用系统默认提供的赋值运算符重载,子类自实现赋值运算符 ...
- 类中赋值运算符重载函数
声明一个字符串类,为这个类型添加赋值运算符 class MyString { public://构造函数MyString(char* pData = NULL);//构造函数MyString(cons ...
- 在c++语言中赋值运算符,C++语言— 类中的赋值运算符重载
赋值运算符重载 赋值运算符的重载在这几个默认的成员函数中的位置也算是举足轻重的,它也是不好理解的一个, 下 面是我自己写的一个复数类,这里面会将赋值运算符重载踏踏实实的过完. 赋值运算符的重载的基本格 ...
- 类的默认成员函数、赋值运算符重载
目录 1.类的6个默认成员函数 2.1 概念 2.1 概念 2.2 特性 3.析构函数 3.1 概念 3.2 特性 4. 拷贝构造函数 4.1 概念 4.2 特征 5.赋值运算符重载 5.1 运算符重 ...
- 运算符重载为类的友元函数
运算符重载为类的友元函数 友元函数通过类的对象可以访问类的公有.保护和私有成员,也就是类的所有成员友元函数都能访问到.所以运算符重载为类的友元函数以后也可以访问类的所有成员. 与运算符重载为成员函数时 ...
- 运算符重载为类的成员函数
运算符重载 运算符重载为类的成员函数后就可以像其他成员函数一样访问本类的数据成员了. 在类的外部通过类的对象,可以像原运算符的使用方式那样使用重载的运算符,比如,"+"运算符被重载 ...
- 一文说尽C++赋值运算符重载函数(operator=)
http://www.cnblogs.com/zpcdbky/p/5027481.html 在前面: 关于C++的赋值运算符重载函数(operator=),网络以及各种教材上都有很多介绍,但可惜的是, ...
- C++基础知识 —— 内存分区模型、引用、函数重载、类和继承、this指针、友元、多态、文件操作
参考 黑马程序员 C++课程笔记,个人理解及整理 可以使用 在线编译c++代码 来简单验证.学习代码 目录 C++核心编程 1. 内存分区模型 1.1 程序运行前 1.2 程序运行后 1.3 ...
最新文章
- R语言构建logistic回归模型并评估模型:构建基于混淆矩阵计算分类评估指标的自定义函数、阳性样本比例(垃圾邮件比例)变化对应的分类器性能的变化、基于数据阳性样本比例选择合适的分类评估指标
- Swift之字符串String的常规操作和处理
- 利用JS实现简单的瀑布流效果
- 理解 | 理解a: float=10
- scala中rdd无法join的问题
- SQL Server之体系结构
- 简单说下COALESCE这个日常使用的函数
- apache mahout_Apache Mahout:入门
- React Native开发指南-在原生和React Native间通信
- PAT甲级题解-1100. Mars Numbers (20)-字符串处理
- django中遇到的错误并解决
- linux ssh原理
- 《Linux编程》上机作业 ·005【进程管理与通信】
- linux不识别xfs,centos7 grub2无法识别xfs root分区
- Vanya and Triangles 暴力枚举
- 解散群通知怎么写_德云社演员私联初二女生,随后德云社全员退出粉丝群,什么情况?...
- lua 常用数据类型总结
- php 数组json失败,php json转数组出错
- arcgis路网密度计算、提取中心线、面积计算
- 关于bit-banding的解释和相关作用(转载)
热门文章
- 博贤科技管理系统漏洞0day
- 单分散磁性二氧化硅微球粒径100nm,浓度可调
- 金属有机骨架mof载药|阿霉素药物载体La/Tm-MOFs@SiO复合材料|PCN-224负载环丙沙星
- eNSP实验五:RIP路由协议
- UVa-10474-大理石在哪
- 大理石在哪儿(Uva10474)
- 【小程序源码合集】云开发前后端完整代码,大学生校园社团体管理活动预约微信小程序源码
- 字节跳动Web Infra发起 Modern.js 开源项目,打造现代 Web 工程体系
- weblogic1213打补丁报错,对 ORACLE_HOME/.patch_storage 没有读权限或写权限
- Hibernate基于主键一对一映射操作实例