运算符重载的一些疑问

文章讨论了C++中的运算符重载,特别是前置和后置递增运算符的重载,强调了左移运算符重载为何通常使用全局函数。同时,文章阐述了非常量引用不能接收临时对象的原因,涉及左值和右值的概念。此外,文章还探讨了对象析构后成员属性的访问问题,分析了临时对象在函数返回过程中的生命周期。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

递增运算符重载函数

#include<iostream>
#include<string>
using namespace std;

class myint
{
friend	ostream& operator<<(ostream& cout,const myint& p);

private:
	int m_num;
public:
	myint()
	{
		m_num = 0;
	}
	myint& operator++()//前置运算符重载函数(引用传递)
	{
		m_num++;
		return *this;
	}

	//myint operator++()//前置运算符重载函数(引用传递)
	//{
	//	m_num++;
	//	return *this;
	//}

	myint operator++(int)//后置运算符重载函数
	{
		myint temp=*this;
		m_num++;
		return temp;
	}
};

ostream& operator<<(ostream& cout,const myint& p)//注意:左移运算符重载尽量别定义用成员函数定义,要用全局函数去定义。
{
	cout << p.m_num << endl;
	return cout;
}

void test01()//前置运算符重载测试(返回值是引用类型的)
{
	myint p1;
	cout <<"++p= "<< ++p1 << endl;
	cout << "运行完++p以后p1.m_num=  " << p1 << endl;
	cout << "++(++p1) " << ++(++p1) << endl;
	cout << "运行完++(++p1)以后p1.m_num=  " << p1 << endl;
}//运行完以后为什么++(++p1) 值为3,因为前面已经执行过一次++p了。

void test02()//前置运算符重载测试(返回不是引用而是对象)
{
	myint p1;
	cout << "++p= " << ++p1 << endl;
	cout << "运行完++p以后p1.m_num=  " << p1 << endl;
	cout << "++(++p1) " << ++(++p1) << endl;
	cout << "运行完++(++p1)以后p1.m_num=  " << p1 << endl;
}

void test03()
{
	myint p2;
	cout << "p2++= " << p2++ << endl;
	cout << "运行完p2++以后p2.m_num=  " << p2 << endl;
}

int main()
{
	test01();
	test03();
}

上面这一段代码,有几个点是需要注意一下的。第一个就是声明左移运算符重载的时候,参数设置问题:
Q1:为什么传参是,myint要传对象,而不是引用,引用的方式test03()就会报错?
这个问题,我思考了一段时间,也在csdn找到了一些答案,说法看似有两种,其实感觉都是讲述同一个东西:就是匿名对象不能被非常引用初始化。
我现在说一下,我自己的见解:运行完后置运算重载函数后,返回的是一个临时的匿名对象。因为临时对象\变量不能被初始化引用,还有种解释:临时、匿名对象具有常性不能作为左值。这里又会牵扯出一个问题就是:
非常量引用为什么不能接收函数的返回值?
要解决这个问题就是得去了解左值与右值(c++真是,越学越废了)。左值在c++11中,可以取地址的、有名字的。右值不能取地址的、没有名字的就是右值。比如int a=b+c;a是一个变量,我们知道a是有自己的地址以及变量名的,显然a就是左值。表达式b+c,以及在函数的返回值,在没有给他赋值一个某一个变量时,我们都不能通过变量名找到他,也叫临时变量,执行完当前行以后,就会销毁。这两个就是典型的右值。

介绍完左值右值,现在说一下非常量左值引用以及常量左值引用。我们常见的int &a=b;就是非常量左值的语法;左值引用就是给该对象取一个别名,没有新开辟了一个内存空间。一般当我们想传入一个参数给函数时,如果使用值传递或者非常量引用传递,是告诉编译器想修改实参的值。我们使用常量引用时,我们想告诉编译器,我们不想改变实参的值。针对临时变量,编译器没有告诉我们,生成临时变量的规则,我们不知道其变量名,自然也无法正常访问到他们,所以当我们使用非常量引用传递这个临时变量时,我们在这个函数里面对这个临时变量进行修改以后,我们也无法得到这个修改的值,因为我们压根找不到他!所以我们不能使用非常量左值引用去引用一个临时变量。
现在我们可以解决左移运算符重载函数形式参数类型的问题了。有两种方法可以解决:
1、使用值传递,直接把这个临时对象copy给形参。
2、使用常量左值引用(常量左值引用是开辟一块空间来储存这个临时变量,所以以后就找的到这个临时变量了,只是用这种方法,函数无法改变这个临时变量的值,这个是和右值引用的区别)

对象析构后,对象里面的成员属性值调用问题

针对这个问题,我写了一段代码:

#include<iostream>
#include<string>
using namespace std;

class   myint
{
public:
	int m_num;
	string name;
	myint(string s)
	{
		this->name = s;
		m_num = 0;
		cout << this->name <<"的构造函数" << endl;
	}
	~myint()
	{
		cout << this->name<<"的运行析构函数" << endl;
	}
};
myint& test01()
{
	myint p1("p1");
	p1.m_num = 1;
	cout << "ssss" << endl;
	return p1;
}//在执行完test01以后,p1明明已经被析构了,而且返回的也是这个对象的引用。也就是说这个引用指向的对象已经被清除了。为什么test还能打印p.num?

void test(myint& p)
{
	cout << "wwww" << endl;
	//p.m_num = 6;
	cout << p.m_num << endl;
}

int main()
{
	myint o("o");
	o= test01();
	test(o);
}

上述代码中,我在test01中,我对 对象屏p1进行了实例化,并且对成员属性进行了修改。我在写完这个代码后,有一个疑问:在运行完tesr01以后,对象不是被析构了吗,按道理p1.m_num=1;这个值将不复存在的。为什么我在后面对象o调用m_num还能输出1呢?
有一些回答是:将test01()的返回值拷贝给对象o的时候,p1还没有被析构。在执行完这一行才会被析构。这一点我是不赞同的(当然,我没有证据)
我得想法是:在o在拷贝p1的成员属性值时,p1已经被析构了,只不过test01()返回了一个匿名对象(这个对象还存着关于p1的信息)又因为临时变量要执行完当前行才会被清除,所以在这个匿名对象被清除时,已经完成o的初始化了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值