网站建设费用计入哪个会计科目,沈阳快速建站公司有哪些,做网站长沙,中国做的电脑系统下载网站好Ⅰ. 运算符重载
引入
❓什么叫运算符重载#xff1f;
就是#xff1a;运用函数#xff0c;将现有的运算符重新定义#xff0c;使其能满足各种自定义类型的运算。
回想一下#xff0c;我们以前运算的对象是不是都是int、char这种内置类型#xff1f;
那我们自定义的“…Ⅰ. 运算符重载
引入
❓什么叫运算符重载
就是运用函数将现有的运算符重新定义使其能满足各种自定义类型的运算。
回想一下我们以前运算的对象是不是都是int、char这种内置类型
那我们自定义的“preson”类型想要进行加减运算该怎么办呢
这就需要运算符重载。 概念
运算符重载是具有特殊函数名的函数
也具有其返回值类型、函数名及参数列表。 函数名关键字operator后面接需要重载的运算符符号。
格式返回值类型 operator 操作符参数列表 1.常用的操作符有、-、*、/、、--、赋值、判断相等、、、、等 2.有几个操作数就有几个形参。 不过当重载成员函数时有一个形参是隐形的即this指针。 ✨说明
1.不能通过连接其他符号来创建新的操作符。
如operator 2.重载操作符必须有一个类类型的参数。
如果参数里没有类类型那运算符重载还有啥意义。 3.用于内置类型的运算符其含义不能改变。
如内置的 整型 不能改变其含义 4.作为类成员函数重载时其形参看起来比操作数少1
因为成员函数的第一个参数为隐藏的this。
(见下面的例子) 5.笔试选择题常考这5个运算符不能重载 .* 点星运算符 : : 域运算符 sizeof 条件运算符 . 点运算符 6.运算符重载写好了以后直接用就行。编译器会自动调用函数。 Date operator(int day){ … } d1100; //直接用。调用会自动完成 举例
class Date
{
public:Date(int year 2000, int month 1, int day 1){_year year;_month month;_day day;} //需要注意的是左操作数是this,指向调用函数的对象bool operator(const Date d) //bool operator(Date*this,const Date d){return _year d._year //其实是this-_yeard._year_month d._month _day d._day;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2023, 8, 12);Date d2(2023, 8, 12);cout (d2 d1) endl;
}
结果为 Ⅱ. 赋值运算符重载
概念
赋值运算符重载作为类的6大成员函数之一
负责将一个对象赋值给另一个对象。
如果我们不写那编译器会自动生成。 格式
T operator const T 参数 ✨说明
1.参数类型为const T。传引用可以提高传参效率。 2.返回类型为T。
❓你可能会疑惑这里只要完成赋值动作的话返回类型为void不就可以了吗
为什么要有返回值呢 有返回值其实是为了支持连续赋值。 如”d1d2d3;“ 要想连续赋值 那d2d3在调用完函数以后要有一个返回值这个返回值作为右操作数参与到d1…中去。 如果返回void那d1空无法完成连续赋值。 所以要想连续赋值就得有返回值。 在返回时我们尽量使用引用返回。
因为能减少传参过程中的拷贝效率更高。
不信我们来实验下
通过对比 传值返回与传引用 调用拷贝构造函数 的次数
来看 传引用究竟有没有减少拷贝
实验组1传值
class Date
{
public:Date(int year 2000, int month 1, int day 1){_year year;_month month;_day day;}Date(const Date d) //我们自己写一个拷贝构造函数{ //这样它每次被调用都会打印出来cout 我被调用了 endl;_year d._year;_month d._month;_day d._day;}Date operator(const Date d) //传值是可以的但是没有引用好{ //实验结果将为我们证明这一点_year d._year;_month d._month;_day d._day;return *this;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2023, 8, 12);Date d2(2023, 8, 12);Date d3(2000, 1, 1);Date d4(2020, 1, 1);d1 d2 d3 d4;
}
结果为这已经是被优化后的结果 实验组2传引用
...Date operator(const Date d) //传引用{_year d._year;_month d._month;_day d._day;return *this;}...
结果为 实验证明传引用比传值调用拷贝构造函数的次数少效率更高。
所以我们能传引用的地方就尽量传引用。 3.检测是否自己给自己赋值。
如果是”d1d1“那这样的赋值完全没意义。
为了更高效我们用if语句来避免自己给自己赋值的情况。
Date operator(const Date d){if (this ! d) //加上判断{_year d._year;_month d._month;_day d._day;return *this;}}
注我们要用this去判断不要用对象
因为对象仅能判断值是否相等而this能从地址判断它俩是否是同一个。 4.返回*this。
为什么可以返回*this
我们知道函数的局部变量是不能返回的
因为局部变量在出了作用域就销毁了。
而这里不同*this是 作用域在函数外面的 对象。
出作用域对象并不会因此销毁。所以*this有效。 只能重载成成员函数
赋值运算符只能重载成成员函数不能重载成全局函数。
因为如果不在类中实现那编译器会生成一个默认的。
此时你在类外实现的全局运算符重载就和默认的那个冲突了。
因此赋值运算符必须定义成成员函数。 赋值or拷贝构造
来看这个例子这两种写法分别是赋值还是拷贝构造 其实都是拷贝构造
赋值操作的是一个已存在的变量而拷贝构造是定义一个新的变量。 默认赋值运算符重载
当你没有显示实现时编译器会自动生成一个默认的赋值运算符重载
以值的方式逐字节拷贝。 注内置类型成员是直接赋值的 而自定义类型成员变量需要调用 对应类的 赋值运算符重载 来完成赋值。 我们演示一下
class Date {
public:Date(int year 2000, int month 1, int day 1){this-_year year;this-_month month;this-_day day;}
private:int _year;int _month;int _day;
};
int main(void)
{Date d1(2010,1,1);Date d2(2023,8,12);//我们并未实现d1 d2; //但这里会自动调用 默认赋值运算符重载return 0;
}
结果 ❓既然默认生成的已经可以完成值的拷贝了那还需要我们自己去实现吗 如果是像日期类这种是不需要的值拷贝已经足够。
但如果涉及资源管理
如动态内存分配、指针、打开的文件等就得深拷贝
这时就必须要自己去实现了。
这里的原因和拷贝构造函数那儿是贯通的。 原因再说明一下
如果有指针而默认的赋值运算符重载只能浅拷贝
并不会再开一块指针指向的空间。
这就导致了两个指针指向同一块空间彼此相互影响。