温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C++中如何实现运算符重载

发布时间:2022-01-21 09:13:23 来源:亿速云 阅读:234 作者:小新 栏目:开发技术

这篇文章主要为大家展示了“C++中如何实现运算符重载”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C++中如何实现运算符重载”这篇文章吧。

1、引例

class Complex { private:     double Real,Image; public:     Complex():Real(0),Image(0)  {}     Complex(double r, double i) : Real(r),Image(i) {}     ~Complex()  {} }; int main() {     Complex c1(1.2,2.3);     Complex c2(45,56);     Complex c3;     c3 = c1.Add(c2);             }

类非常简单,下面我们要讨论如何写一个Add函数,使得两个对象的属性相加,返回一个新的对象。

第一种:

Complex::Complex Add(const Complex &c) {     Complex co;     co.Real = this->Real + c.Real;     co.Image = this->Image + c.Image;     return co; }

问题1:如何写出最节省空间的Add函数?

第二种:

Complex::Complex Add(const Complex &c) const {     return Complex(c.Real + this->Real, c.Image + this.Image); }

由于不需要改变调用对象的属性值,我们给this指针添加const 修饰。

分析过程如下:

C++中如何实现运算符重载

问题2:为什么第一种方式不节省空间呢?

首先第一种的代码比较繁琐,并且在函数栈帧中又创建了一个对象(第3行)。并且函数类型是值传递类型(第6行),返回的是一个将亡值对象。那么整个Add函数空间会产生两个对象,造成空间的浪费。

第二中代码创建的是无名对象,减少了一个co对象的创建,并且将无名对象直接作为将亡值对象传递给main函数中的c3。

问题3:我们能否将Add函数改为引用类型,这样来减少将亡值对象的创建

Complex::Complex &Add(const Complex &c) const {     return Complex(c.Real + this->Real, c.Image + this.Image); }

VS2019发现报错,不能返回引用对象:

C++中如何实现运算符重载

我们进行分析:

C++中如何实现运算符重载

问题4:我们能否将这个Add函数名改为 + 运算符?

//Complex::Complex Add(const Complex &c) const Complex::Complex +(const Complex &c) const  {	Complex co;	co.Real = this->Real + c.Real;	co.Image = this->Image + c.Image;	return co; } int main() {     ...     //c3 = c1.Add(c2);       c3 = c1.+(c2);    //将原先Add的地方改变为加号。     ... }

这样使用,编译器又会报错,操作符不可作为一个有效的函数名来被使用

问题5:如何使 +预算符 作为函数名使用?

这就引出了今天的关键,函数运算符重载

在C++中,为了使操作符作为一个有效的函数名,我们在操作符前面添加一个operator

Complex operator+(const Complex &c) const  {      return Complex(c.Real + this->Real,c.Image + this->Image); } int main() {      Complex c1(1.2,2.3);      Complex c2(10,10);      Complex c3;      c3 = c1 + c2;           //上面一行实际上是      //c3 = c1.operator+ (c2);      //c3 = operator+(&c1,c2);  //编译器还会经过一次编译 }

前面几篇博客已经分析了第15行的由来,是将c1的地址传递给this指针,将c2作为形参c的别名传递给函数。

2、类中自动建立的函数

在C++中,如果我们定义一个类,它会给我们自动创建六个缺省函数

构造函数析构函数拷贝构造函数赋值函数普通对象的&(取地址符)的重载常对象的&(取地址符)重载

代码示例如下:

class Object { public:     Object()    {}	//构造函数     ~Object()   {}	//析构函数     Object(const Object &obj)   {}	//拷贝构造函数     Object &operator=() {const Object &obj} //赋值函数     {         return *this;     }          Object *operator&()	//普通对象的&(取地址符)的重载     {         return this;     }          const Object *operator&() const	//常对象的&(取地址符)重载     {         return this;     } };

然后,在C11标准下,又增添了两个缺省函数,这里不做深究:

移动构造函数移动赋值函数

3、重载赋值运算符解析

回到最初的例子:

class Object {     int value; public:     Object ()   {         cout << "create:" << this << endl;     }                  //普通构造函数     Object (int x = 0):value(x) {cout << "create:" << this << endl;}  //缺省构造函数     ~Object()                       //析构函数     {         cout << "~Objcet() " << this << endl;     }     Object(Object &obj):value(obj.value)                  {         cout << "Copy create:" << this << endl;     }     int & Value()     {         return value;     }     const int &Value() const      {         return value;     }                Object &operator=(const Object& obj)        //此处加引用     {         this->value = obj.value;         return *this;       //this指针指向objb的地址。赋值函数结束后,objb不会被消亡,所以可以以引用返回     }     	void operator=(const Object& obj)       //赋值语句不可给this指针加const     {         this->value = obj.value;     }      }; int main() {     Object objx(0);     Object objy(0);     objy = fun(objx);     cout << objy.Value() << endl;     return 0; }

我们在34行添加一个等号运算符重载函数: void operator=(const Object& obj)

此处不可添加const修饰this指针,因为需要使用this指针作为左值被修改。

问题6:void operator=(const Object& obj) 只能用于 obja = objb,为什么不可以这样使用 obja = objb = objc;

我们逐一分析:

obja = objb = objc; //当调用等号运算符函数的时候。 obja = objb.operator = (objc); obja = operator = (&objb,objc); //如果此处是调用的是 void operator=(const Object& obj) ; //等号从右向左指向,我们不能把一个void 类型赋给一个obja对象类型。

我们将赋值运算符进行再次重载,丢弃 void 版本:

Object &operator=(const Object& obj)        //此处加引用 {	this->value = obj.value;	return *this;       //this指针指向objb的地址。赋值函数结束后,objb不会被消亡,所以可以以引用返回 }

这样就可以使用了。

我们接着上次的深入分析:

obja.operator=(operator=(&objb,objc)); operator=(&obja,operator=(&objb,objc));

问题7:如果遇到obja = obja这种情况,如何赋值呢?

回答:对this指针和形参引用进行判断。

Object &operator=(const Object &obj) {     if(this != &obj)     {         this->value = obj.value     } }

问题8:为什么函数是在栈区构建的,以引用返回打印的不是一个随机值?

运行程序,VS2012中,打印的是一个随机值。

VS2019打印的是一个正常值。

c));

> 问题7:如果遇到obja = obja这种情况,如何赋值呢? > > 回答:对this指针和形参引用进行判断。 ```cpp Object &operator=(const Object &obj) {     if(this != &obj)     {         this->value = obj.value     } }

问题8:为什么函数是在栈区构建的,以引用返回打印的不是一个随机值?

运行程序,VS2012中,打印的是一个随机值。

VS2019打印的是一个正常值。

在WIN10系统中,VS2019与操作系统完全结合,安全性更高。当程序多次运行的时候,它的逻辑地址都不一样,这样做的好处是:当病毒入侵时,由于程序的逻辑地址是变化的,病毒不好寻找入侵的入口。

以上是“C++中如何实现运算符重载”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

c++
AI