C++中的运算符重载详解

 更新时间:2022年01月20日 16:10:14   作者:看书就头疼  
大家好,本篇文章主要讲的是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 修饰。

分析过程如下:

在这里插入图片描述

问题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发现报错,不能返回引用对象:

在这里插入图片描述

我们进行分析:

在这里插入图片描述

问题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++中的运算符重载详解的文章就介绍到这了,更多相关C++运算符重载内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 探究在C++程序并发时保护共享数据的问题

    探究在C++程序并发时保护共享数据的问题

    这篇文章主要介绍了探究在C++程序并发时保护共享数据的问题,也有利于大家更好地理解C++多线程的一些机制,需要的朋友可以参考下
    2015-07-07
  • 详细谈谈C语言中动态内存

    详细谈谈C语言中动态内存

    在C语言中,编写程序的时候不能确定内存的大小,希望程序在运行的过程中根据数据量的大小动态的分配内存,这篇文章主要给大家介绍了关于C语言中动态内存的相关资料,需要的朋友可以参考下
    2022-03-03
  • C语言获取文件长度的方法

    C语言获取文件长度的方法

    这篇文章主要介绍了C语言获取文件长度的相关知识,包括使用标准库方法和使用Linux系统调用,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-10-10
  • C++解析ini文件的实现方法

    C++解析ini文件的实现方法

    在C++编程中,有时我们需要处理配置文件来存储应用程序的设置和参数,而INI文件是一种常见的选择,这篇文章主要给大家介绍了关于C++解析ini文件的实现方法,需要的朋友可以参考下
    2024-08-08
  • C/C++预处理浅析使用形式

    C/C++预处理浅析使用形式

    预处理是指在进行编译的词法扫描和语法分析之前所作的工作。预处理指令指示在程序正式编译前就由编译器进行的操作,可放在程序中任何位置。处理完毕自动进入对源程序的编译。C/C++中的预处理主要包含三种:文件包含、宏定义、条件编译
    2022-09-09
  • C++超详细讲解函数对象

    C++超详细讲解函数对象

    在c++中,我们把所有能当作函数使用的对象统称为函数对象。它是实现operator()的任何类型,此运算符被称为调用运算符,当调用此操 作符时,其表现形式如同普通函数调用一般,因此取名叫函数对象
    2022-06-06
  • QT应用启动失败排查方法小结

    QT应用启动失败排查方法小结

    启动QT应用经常会碰到应用启动失败,qt platform plugin无法启动,本文就来介绍一下QT应用启动失败排查方法小结,具有一定的参考价值,感兴趣的可以了解以下
    2023-09-09
  • C++中getline()的用法详解

    C++中getline()的用法详解

    这篇文章主要介绍了C++中getline()的用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02
  • Seesion在C++服务端的使用方法

    Seesion在C++服务端的使用方法

    这篇文章主要介绍了Seesion在C++服务端是怎么使用的?本文给出了解决方案和实例代码供大家参考,需要的朋友可以参考下
    2020-02-02
  • 关于C++使用指针 堆和栈的区别分析

    关于C++使用指针 堆和栈的区别分析

    本篇文章小编为大家介绍,关于C++使用指针 堆和栈的区别分析。需要的朋友参考下
    2013-04-04

最新评论