哈喽各位铁汁们好啊,我是博主鸽芷咕《C++干货基地》是由我的襄阳家乡零食基地有感而发,不知道各位的城市有没有这种实惠又全面的零食基地呢?C++ 本身作为一门篇底层的一种语言,世面的免费课程大多都没有教明白。所以本篇专栏的内容全是干货让大家从底层了解C++,把更多的知识由抽象到简单通俗易懂。
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。
C++ 中为了增加代码的可读性运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
🔥 注意:
.*
::
sizeof
? :
.
注意以上5个运算符不能重载。这个经常在笔试选择题中出现。**下面我们就来实践一下再日期类中 ==
运算符如何重载, 以往我们在 内置类型 ==
运算符返回的都是bool 类型
返回值类型 operator操作符(参数列表)
🍸 代码演示:
classDate{public:Date(intyear,intmonth,intday){_year =year;_month =month;_day =day;}booloperator==(constDate&d1){return_year ==d1._year &&_month ==d1._month &&_day ==d1._day;}private:int_year;int_month;int_day;};intmain(){Date d1(2022,1,13);Date d2(2022,1,14);Date d3(2022,1,13);cout <<(d1 ==d2)<<endl;cout <<(d1 ==d3)<<endl;return0;}
< 运算符重载就更加简单了,和 运算符 == 的规则一样只需要改变一下我们类成员的比较方法就可以了
🍸 代码演示:
classDate{public:Date(intyear,intmonth,intday){_year =year;_month =month;_day =day;}booloperator==(constDate&d1){return_year ==d1._year &&_month ==d1._month &&_day ==d1._day;}booloperator<(constDate&d1){if(_year <d1._year){returntrue;}elseif(_year ==d1._year){if(_month <d1._month){returntrue;}else{return_day <d1._day;}}returnfalse;}private:int_year;int_month;int_day;};intmain(){Date d1(2022,1,13);Date d2(2022,1,14);Date d3(2022,1,13);cout <<(d1 <d2)<<endl;cout <<(d1 <d3)<<endl;return0;}
前面的几个赋值运算符重载比较简单,只是为了完成类是如何比较的而赋值运算符就是我们这里比较关键的了
赋值运算符重载
主要是赋值,把一个对象赋值给另一个对象- 而
拷贝构造函数
主要是,同类型的对象创建初始化时调用
这里我们为什么要讲返回值类型设定为
&
引用类型呢?赋值运算不就简单赋值就好了:
- 那么我们就来看一下下面这段代码
classDate{public:Date(intyear=2022,intmonth=10,intday=21){_year =year;_month =month;_day =day;}booloperator==(constDate&d1){return_year ==d1._year &&_month ==d1._month &&_day ==d1._day;}booloperator<(constDate&d1){if(_year <d1._year){returntrue;}elseif(_year ==d1._year){if(_month <d1._month){returntrue;}else{return_day <d1._day;}}returnfalse;}booloperator!=(constDate&d){return~(*this==d);}voidoperator=(constDate&d){_year =d._year;_month =d._year;_day =d._day;}private:int_year;int_month;int_day;};intmain(){Date d1(2022,1,13);Date d2;Date d3;d2 =d3 =d1;inta,b;a =b =10;return0;}
这里为什么内置类型可以连续赋值而自定类型不可以?内置类型我们都知道是从后往前连续赋值的
二元 “=”
运算符没有找到与它匹配的操作数所以我们的返回值就必须是this 指针所指向的内容代码改进如下:
classDate{public:Date(intyear=2022,intmonth=10,intday=21){_year =year;_month =month;_day =day;}booloperator==(constDate&d1){return_year ==d1._year &&_month ==d1._month &&_day ==d1._day;}booloperator<(constDate&d1){if(_year <d1._year){returntrue;}elseif(_year ==d1._year){if(_month <d1._month){returntrue;}else{return_day <d1._day;}}returnfalse;}booloperator!=(constDate&d){return~(*this==d);}Date&operator=(constDate&d){if(*this!=d){_year =d._year;_month =d._year;_day =d._day;}return*this;}private:int_year;int_month;int_day;};intmain(){Date d1(2022,1,13);Date d2;Date d3;d2 =d3 =d1;return0;}
多加了一个 if 判断是为了避免
d1 = d1;
这样的写法去又重新赋值一遍
赋值运算符重载既然也是六大默认成员函数之一那么肯定也是我们不写自动生成一个默认的复制运算符重载 ,那么究竟有什么行为呢?
构造函数和析构函数他们的行为都是对内置类型不处理对自动定义类型调用他们的析构或者构造函数,而 赋值运算符重载是和 拷贝构造一样的行为,我们不写会自定生成一个默认函数,默认的赋值运算符重载 以值的方式逐字节拷贝。
答案是肯定的,自动生成的
默认赋值重载
只会完成浅拷贝,也就是值拷贝当遇到需要申请资源
的类时 就会出现问题!
- 默认生成的赋值重载只完成值拷贝会把俩个指针的指向都改为同一个方向就会导致程序崩溃
typedefintDataType;classStack{public:Stack(size_t capacity =10){_array =(DataType*)malloc(capacity *sizeof(DataType));if(nullptr==_array){perror("malloc申请空间失败");return;}_size =0;_capacity =capacity;}voidPush(constDataType&data){// CheckCapacity();_array[_size]=data;_size++;}~Stack(){if(_array){free(_array);_array =nullptr;_capacity =0;_size =0;}}private:DataType*_array;size_t _size;size_t _capacity;};intmain(){Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2;s2 =s1;return0;}
这里s2 的指针被 s1 所指向的地址给以值的方式赋值了,所以 s2 s1 指向的是同一块空间当他们自动调用析构函数时就会对同一块地址释放俩次导致程序崩溃
前面我们重载的都是二元的运算符,看似只有一个显示定义的参数其实还有一个this指针
- 例如d1 == d2虽然我们是这样写的但是会转换为
- d1.operator==(d2)这样的,那前置 ++ 和后置++ 都是一元操作符且运算符都是一样的如何进行重载呢?
下面我们就来尝试重载一下前置++,前置++ 我相信大家都用过返回的是++之后的值
🍸 代码演示:
Date&operator++(){_day++;return*this;}
而我们的后置++ 返回的是++之前的值先使用在++所以需要返回+1之前的旧值,故需在实现时需要先将this保存一份,然后给this+1
后置++:
Date operator++(int){Date tmp(*this);_day +=1;returntmp;}