您的位置:首页 > 健康 > 美食 > 知末网官网_app运营成本估算_百度数据分析工具_360指数官网

知末网官网_app运营成本估算_百度数据分析工具_360指数官网

2025/5/11 7:14:09 来源:https://blog.csdn.net/jp_yc/article/details/146113984  浏览:    关键词:知末网官网_app运营成本估算_百度数据分析工具_360指数官网
知末网官网_app运营成本估算_百度数据分析工具_360指数官网

目录

​编辑

一、运算符重载

1.1 运算符重载概念

1.2 全局运算符重载

1.3 运算符重载为成员函数

二、赋值运算符重载的特性

2.1 赋值运算符重载需要注意的点

2.2 赋值运算符重载格式

2.2.1 传值返回

2.2.2 传引用返回

2.2.3 检查自己给自己赋值

三、赋值运算符重载的应用

四、总结


一、运算符重载

1.1 运算符重载概念

        C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数。也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

这里虽然用了重载,但是运算符重载和函数重载不是一个东西:

        函数重载:允许函数名相同参数不同的函数存在;

        运算符重载:让自定义类型的对象可以用运算操作符(必须是C\C++语法存在的运算符)。

函数名字为:关键字operator后面接需要重载的运算符符号。

函数原型:返回值类型 operator 操作符 (参数列表)

1.2 全局运算符重载

使用全局的operator==,程序如下:

#include<iostream>
using namespace std;class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//private:int _year;int _month;int _day;
};bool operator==(const Date& d1, const Date& d2)
{return d1._year == d2._year&& d1._month == d2._month&& d1._day == d2._day;
}int main()
{Date d1(2025, 3, 8);Date d2(2025, 3, 7);cout << (d1 == d2) << endl;//cout << (operator==(d1, d2)) << endl;//两种写法是一样的return 0;
}

        上述程序中,全局的运算符重载的形式为:bool operator==(const Date& d1, const Date& d2),这就需要把Date类的成员变量改为私有,即注释掉private。

        注:赋值运算符重载成全局函数,注意重载成全局函数时没有this指针了,需要给两个参数。

        那么这样操作,就破坏了Date类的封装性。封装性如何保证?

  1. 使用友元函数;
  2. 重载为成员函数(常用)。

1.3 运算符重载为成员函数

        将上述程序作进一步修改:

#include<iostream>
using namespace std;class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}bool operator==(const Date& d){return this->_year == d._year&& this->_month == d._month&& this->_day == d._day;}private:int _year;int _month;int _day;    
};int main()
{Date d1(2025, 3, 8);Date d2(2025, 3, 7);cout << (d1 == d2) << endl;cout << d1.operator==(d2) << endl;//两种写法是一样的return 0;
}

        运算符重载为成员函数的形式为:bool operator==(const Date& d),这里需要注意的是,左操作数是this,指向调用函数的对象。

1.4 运算符重载需要注意的点

运算符重载的使用需要注意一下5点:

        1. 不能通过连接其他符号来创建新的操作符:比如operator@;

        2. 重载操作符必须有一个类类型参数;

        3. 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义;

        4. 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐
藏的this;

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

        针对5中的.*,可以写如下程序:

class ob
{
public:void func(){cout << "void func()" << endl;}
};typedef void(ob::*pobfunc)()int main()
{pobfunc p = &ob::func;//成员函数取地址,要用&操作符,不然取不到//等同于void (ob:: *pi)() = &ob::func;ob tmp;(tmp.*p)();//通过对象去调用成员函数的指针,成员函数指针要传this//*p();//普通的函数指针的调用return 0;
}

        函数指针和数组指针都是特殊的指针,普通变量的重命名为:typedef 类型 重命名

        上述程序中,typedef void(ob::*pobfunc)()成员函数指针类型的重定义。其中,pobfunc是指向ob类中成员函数的函数指针类型。

1. void (ob*::)()

        函数指针类型,它指向一个返回值为void,且没有参数的成员函数。ob*::表示函数指针指向ob类的成员函数。

2. typedef void(ob*::pobfunc)()

        使用typedef关键字重定义一个指向ob类中的成员函数的函数指针类型pobfunc。

二、赋值运算符重载

2.1 赋值运算符重载格式

  • 参数类型const Date&,传递引用可以提高传参效率;
  • 返回值类型Date&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值;
  • 检测是否自己给自己赋值
  • 返回*this 要复合连续赋值的含义

        相较于传值传参和传引用传参。 

2.1.1 传值返回

        将1.3的程序在Date类中进行补充,补充的程序为:

Date operator=(const Date& d2)
{this->_year = d2._year;this->_month = d2._month;this->_day = d2._day;return *this;//*this就是d1,相当于拿到左操作数
}

        因为,Date operator=(const Date& d)中的Date表明是传值返回,意味着return *this;不会返回*this而是返回它的拷贝(拷贝以后或存放在寄存器中)。

        所以,同类型的传值拷贝又会调用一个拷贝构造。

2.1.2 传引用返回

        将1.3的程序在Date类中进行补充,补充的程序为:

Date& operator=(const Date& d2)
{this->_year = d2._year;this->_month = d2._month;this->_day = d2._day;return *this;//*this就是d1,相当于拿到左操作数
}

2.1.3 检查自己给自己赋值

        这可能会造成性能的浪费;成员变量可能依赖于其他成员变量的值,如果这些成员变量的值被覆盖,可能会引发错误。

        基于2.2.2,可通过判断地址来进一步改写:

Date& operator=(const Date& d2)
{if(this != &d2){this->_year = d2._year;this->_month = d2._month;this->_day = d2._day;}return *this;
}

2.2 赋值运算符只能重载成类的成员函数

        C++规定,其他运算符可以重载成全局的,赋值重载不可以,只能重载为成员函数。 

        对于默认成员函数,如果不写,编译器会生成一份。如果放在全局,类中没有,编译器会生成一份,那调用的时候会产生冲突。 

class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}int _year;int _month;int _day;
};
// 赋值运算符重载成全局函数,注意重载成全局函数时没有this指针了,需要给两个参数Date& operator=(Date& left, const Date& right)
{if (&left != &right){left._year = right._year;left._month = right._month;left._day = right._day;}return left;
}// error C2801: “operator =”必须是非静态成员

2.3 没有显式,编译器会生成一个默认赋值运算符重载

        不写赋值运算符重载,编译器会不会生成默认的呢? - 会,因为是6个默认成员函数之一。

        默认生成的对内置类型会完成值拷贝(浅拷贝),对自定义类型会去再调用它的赋值。

        怎么知道赋值默认生成的赋值的行为是什么? - 同拷贝构造。

        那是不是意味着自定义赋值操作符重载就可以不写了呢? - 不是。

        注意:如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必
须要实现。 

三、赋值运算符重载的应用

        如果是内置类型,编译器是可以调用相关指令的;如果是自定义类型,编译器首先会去看有没有重载运算符,如果没有就会报错。

#include<iostream>
using namespace std;class Date
{
public:Date(int _year = 1, int _month = 1, int _day = 1){_year = year;_month = month;_day = day;}Date& operator=(const Date& d){if(this != &d){this->_year = d._year;this->_month = d._month;this->_day = d._day;}return *this;}Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};int main()
{Date d1(2025, 3, 9);Date d2(2025, 3, 9);d1 = d2;Date d3(d1);d1 = d2 = d3;//自定义类型,连续赋值是要有返回值的d3.Print();int i, j = 0;cout << (i = j = 10) << endl;return 0;
}

        程序Date d3(d1);为拷贝构造,还是一个构造。构造是指对象创建实例化的时候自动调用的初始化。其他的构造可能是用一些普通的参数进行初始化,而拷贝构造是用同类型一个存在的对象进行初始化要创建的对象。

        程序d1 = d2;,已经存在的两个对象,一个拷贝赋值给另一个,这里边用到了=运算符,所以就要重载这个运算符。

        程序d1 = d2 = d3;为自定义类型,连续赋值是要有返回值的。

        程序i = j = 10;,内置类型支持连续赋值。执行动作为:10赋值给j作为一个表达式,这个表达式有返回值,返回值就是左操作数j。同理,再向左,返回值为左操作数i。

四、总结

默认生成的函数行为总结:

  • 构造和析构:内置类型不处理,自定义类型调用对应的构造和析构。
  • 拷贝构造和赋值运算符重载:内置类型值拷贝,自定义类型调用对应的拷贝构造和赋值重载。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com