服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C语言运算符的重载详解

C语言运算符的重载详解

2022-08-30 12:07悲伤土豆拌饭 C/C++

大家好,本篇文章主要讲的是C语言运算符的重载详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下

写一个Add函数

我们先讨论下面代码,并复习前面的内容

class Complex
{
private:
	double Real, Image;
public:
	Complex() :Real(0), Image(0) {}
	Complex(double r, double i) :Real(r), Image(i) {}
	~Complex() {}
	//Complex Add(const Complex* const this,const Complex &c)
	Complex Add(const Complex& x)const
	{
		Complex y;
		y.Real = Real + x.Real;
		y.Image = Image + x.Image;
		return y;
		//return Complex(this->Real + x.Real, this->Image + x.Image);
	}
	void Print()
	{
		cout << Real << "+" << Image << "i" << endl;
	}

};
int main()
{
	Complex c1(12, 23);
	Complex c2(4.5, 5.6);
	Complex c3;
	c3 = c1.Add(c2);
	c3.Print();

	return 0;
}

C语言运算符的重载详解

直接return可以使用无名函数直接代替将亡值对象,相比可以省一次对象的构建

我们再分析如果我们使用引用返回Add函数

const Complex& Add(const Complex& x)const
	{
		Complex y;
		y.Real = Real + x.Real;
		y.Image = Image + x.Image;
		return y;
		//return Complex(this->Real + x.Real, this->Image + x.Image);
	}

C语言运算符的重载详解

若我们以引用返回,将亡值对象会创建在Add函数的栈帧中,然后返回将亡值地址,函数return结束该空间会被释放、

若没有引用,构建无名对象也就是将亡值对象会构建在主函数的空间中,这里使用将亡值对象值给到c3是没有问题的

我们查看对象的构造与析构

class Complex
{
private:
	double Real, Image;
public:
	Complex() :Real(0), Image(0) {}
	Complex(double r, double i) :Real(r), Image(i) 
	{ 
		cout << "Create:" << this << endl; 
	}
	Complex(const Complex& x):Real(x.Real),Image(x.Image)
	{
		cout << "Copy Create:" << this << endl;
	}
	~Complex()
	{
		cout << "~Complex:" << this << endl;
	}
	//Complex Add(const Complex* const this,const Complex &c)
	Complex Add(const Complex& x)const
	{
		return Complex(this->Real + x.Real, this->Image + x.Image);
	}
	void Print()
	{
		cout << Real << "+" << Image << "i" << endl;
	}

};

int main()
{
	Complex c1(12, 23);
	Complex c2(4.5, 5.6);
	Complex c3;
	c3 = c1.Add(c2);
	c3.Print();

	return 0;
}

C语言运算符的重载详解

首先我们使用引用返回需要加上const修饰,这是因为我们返回将亡值在临时空间具有常性,所以普通引用是不能进行返回的,需要使用常引用返回

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

我们发现对临时对象的构建后马上就进行析构,那么是怎么将数据拿出给到c3的?这个在最后我们进行分析

 

为什么不用加号作为函数名

//Complex operator+(const Complex* const this,const Complex &c)
Complex operator+(const Complex &c) const
{
	return Complex(this->Real + x.Real, this->Image + x.Image);
}

这里是不可以的,加号是一个操作符,不能使用操作放作为有效的函数名称;但是在C++中为了使这些操作符号能够当作函数名,那么我们需要在前面加上一个关键字operator

//Complex operator+(const Complex* const this,const Complex &c)
Complex operator+(const Complex &c) const
{
	return Complex(this->Real + x.Real, this->Image + x.Image);
}
也就是告诉编译器,加号是一个有效的函数名,这就叫做运算符的重载;随后我们之间使用 c3 = c1 + c2 就是可以的
int main()
{
	Complex c1(12, 23);
	Complex c2(4.5, 5.6);
	Complex c3;
	c3 = c1 + c2;
	//编译器编译会是下面的情况
	//c3 = c1.operator+(c2);
	//c3 = operator+(&c1,c2); 加上this指针
}

 

运算符的重载

一个对象,编译器会给它有6个缺省函数

C语言运算符的重载详解

我们再来看下面这个问题

//我们写一个赋值运算符重载
void operator=(const Object& obj)
{
	this->value = obj.value;
}
//返回类型为void,这样不可以就不可以连等
//obja = objb = objc;
//obja = objb.operator=(objc);
//obja = operator=(&objb,objc); 返回的无类型,不能给obja赋值

且赋值函数不可以定义为const修饰

Object& operator=(const Object& obj)
{
	this->value = obj.value;
	return *this;
}
obja = objb = objc;

//改写
obja = objb.operator=(objc);
obja = operator=(&objb,objc);

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

通过返回对象,就可以实现连等;并且我们可以通过引用返回,因为此对象的生存期并不受函数的影响,不会产生一个临时对象作为一个过度

防止自赋值
若是我们将obja给obja赋值,也就是自赋值

obja = obja
operator=(&obja,obja);

我们就需要进行一步判断

Object& operator=(const Object& obj)
{
	if(this != &obj)//防止自赋值
	{
		this->value = obj.value;
	}
	return *this;
}

 

上面问题解决

我们通过这段代码来看,与上面问题相同

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

};
Object& fun(const Object& obj)
{
	int val = obj.Value() + 10;
	Object obja(val);
	return obja;
}

int main()
{
	Object objx(0);
	Object objy(0);
	objy = fun(objx);
	cout << objy.Value() << endl;
	return 0;
}

我们在这里希望通过引用返回,这里return的临时对象会构建在fun函数的栈帧中,并且在函数结束栈帧释放,随后调用赋值运算符重载,但是数值依旧是正确的

C语言运算符的重载详解

我们跟踪这个被析构对象的地址,首先我们定位在fun函数的return obja;,随后进入析构函数将我们的obja进行析构

C语言运算符的重载详解

接着运行到回到主函数进行赋值,接着进入赋值运算符重载,可以看到,这里的obj地址与已被析构的obja地址相同

C语言运算符的重载详解

C语言运算符的重载详解

可以看到这个值依旧存在,依旧可以打印给出,这是因为vs2019的特殊性质造成的;我们每次运行程序会发现每次的对象地址都在变化,逻辑地址会随机改变,被析构对象的栈帧不会被接下来的赋值运算符重载扰乱地址空间,所以即使我们引用返回的对象已经死亡依旧可以将数值正确返回

但是在vc中,我们得到的值会是随机值,这是因为vc中每次运行程序地址都不会改变,当我们从fun函数退出进入赋值语句中,就会将原本存储数据的地址扰乱,继而变成了随机值

尽管我们引用返回能够将数据正确打印,但是该对象已经死亡,这是不安全的,所以我们一定不要以引用返回对象

C语言运算符的重载详解

VS2019具有一个特点:当我们调用函数,若函数中没有定义局部变量或局部对象时,该函数基本不对栈帧进行清扫

总结

到此这篇关于C语言运算符的重载详解的文章就介绍到这了,更多相关C语言运算符重载内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/XXXTENTAC1ON/article/details/122516932

延伸 · 阅读

精彩推荐
  • C/C++C语言 用指针作为函数返回值详解

    C语言 用指针作为函数返回值详解

    本文主要介绍C语言 用指针作为函数返回值,这里整理了相关资料及示例代码,帮助大家学习理解此部分知识,有需要的同学可以参考下...

    C语言教程网6012021-04-14
  • C/C++C语言实现词法分析器

    C语言实现词法分析器

    这篇文章主要为大家详细介绍了C语言实现词法分析器,一个简单的词法分析程序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    flamingobaby7262021-07-20
  • C/C++C++动态联编介绍

    C++动态联编介绍

    这篇文章主要介绍了C++动态联编,在C++中,联编是指一个计算机程序的不同部分彼此关联的过程。按照联编所进行的阶段不同,可分为两种不同的联编方法...

    梁唐11462022-08-09
  • C/C++C语言编写获取Linux本地目录及本机信息的小程序实例

    C语言编写获取Linux本地目录及本机信息的小程序实例

    这篇文章主要介绍了C语言编写获取Linux本地目录及本机信息的小程序实例,小程序能够根据参数输出目录的结构以及获取主机用户的信息,需要的朋友可以参...

    张大鹏4722021-03-30
  • C/C++浅谈C++类型转换几种情况

    浅谈C++类型转换几种情况

    本文主要介绍了几种C++类型转换,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    花狗Fdog9372021-12-13
  • C/C++详解在C++中显式默认设置的函数和已删除的函数的方法

    详解在C++中显式默认设置的函数和已删除的函数的方法

    这篇文章主要介绍了在C++中显式默认设置的函数和已删除的函数的方法,文中讲到了C++11标准中的新特性,需要的朋友可以参考下...

    C++教程网8752021-03-22
  • C/C++c++读取excel的代码详解

    c++读取excel的代码详解

    在本篇文章里小编给大家分享的是一篇关于c++读取excel的代码详解内容,需要的朋友们可以学习参考下。...

    藏色散人10542021-08-17
  • C/C++OpenCV选择图像中矩形区域并保存

    OpenCV选择图像中矩形区域并保存

    这篇文章主要为大家详细介绍了OpenCV选择图像中矩形区域并保存的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    大唐游子7732021-07-19