C++左值、右值及引用

Lionheartch 2013-04-08 03:43:51
小弟在学习C++lvalue,rvalue引用中遇到一困惑,如下
#include<iostream>
#include"stdlib.h"
using namespace std;
class Cmessage
{
private:
char* pmessage;
public:
Cmessage(const char* text = "default message.")
{
pmessage = new char[strlen(text)+1];
strcpy(pmessage,text);
cout<<"instructor."<<endl;
}
~Cmessage()
{
delete []pmessage;
cout<<"destructor."<<endl;
}
void showit()
{
cout<<pmessage<<endl;
}
Cmessage(Cmessage& amess)
{
pmessage = amess.pmessage;
amess.pmessage = NULL;
cout<<"fuzhigouzao."<<endl;
}
Cmessage& operator=(Cmessage& amess)
{
if(this->pmessage==amess.pmessage)
return *this;
delete [] pmessage;
this->pmessage = amess.pmessage;
amess.pmessage = NULL;
cout<<"overload ="<<endl;
return *this;
}
Cmessage operator+(const Cmessage& amess)const
{
cout<<"overload +"<<endl;
size_t len = strlen(this->pmessage)+strlen(amess.pmessage)+1;
Cmessage message;
message.pmessage = new char[len];
strcpy(message.pmessage,this->pmessage);
strcat(message.pmessage,amess.pmessage);
return message;
}
};
int main()
{
Cmessage text1("text1 message.");
Cmessage text2("text2 message.\n");
Cmessage text3;
cout<<"text3 = text1+text2"<<endl;
text3 = text1+text2; //**************//
text3.showit();
return 0;
}

如上,注释处的赋值为什么还能调用text3.operator=()呢?text1+text2返回值不是应当是右值吗?text3.operator=()的形参是左值引用啊。这里为什么不报错呢?运行结果如下:
instructor.
instructor.
instructor.
text3 = text1+text2
overload +
instructor.
fuzhigouzao.
destructor.
overload =
destructor.
text1 message.text2 message.

destructor.
destructor.
destructor.
...全文
528 31 打赏 收藏 转发到动态 举报
写回复
用AI写文章
31 条回复
切换为时间正序
请发表友善的回复…
发表回复
_uniqs 2013-04-11
  • 打赏
  • 举报
回复
你要真想知道每行代码的实际意义,,,去好好啃下汇编,然后跟汇编码吧。
_uniqs 2013-04-11
  • 打赏
  • 举报
回复
引用 21 楼 vipxuliang 的回复:
引用 19 楼 u_1_n_2_i_3 的回复:so easy 的问题。。。加出来的结果它也是一个左值。 class A { ... }; A a1,a2; ***.operator=(a1+a2); 这一行翻译过来就是,把a2加到a1上,加之前,a1是左值,a2是右值 加完依然是个左值。 或者你可以写一个函数 abc(A&amp; rhs);……
int是基本类型。你把两个int加在一起,产生的是一个具体的值。 int a = 3; int b = 4; a+b 是一个具体的数值7. 如果是自定义类型,加在一起,一个临时对象。你可以取地址看一下 ABC a; ABC b; cout<<&a<<endl; cout<<&b<<endl; cout<<a+b<<endl; 功底深点的应该从这里的代码一眼就可以看出来 Cmessage operator+(const Cmessage& amess)const { cout<<"overload +"<<endl; size_t len = strlen(this->pmessage)+strlen(amess.pmessage)+1; Cmessage message; message.pmessage = new char[len]; strcpy(message.pmessage,this->pmessage); strcat(message.pmessage,amess.pmessage); return message; } 它返回的是一个CMessage的对象。注意这里是对象实体,不是指针。是可以这样写的。对象不会在operator+函数退出后消失的无影无踪。当然如果是指针也是可以这样写的,只不过一个是栈上操作一个是堆上内存。
zhangxun2007 2013-04-11
  • 打赏
  • 举报
回复
初学者,学习中。。。
_uniqs 2013-04-11
  • 打赏
  • 举报
回复
引用 22 楼 vipxuliang 的回复:
引用 19 楼 u_1_n_2_i_3 的回复:so easy 的问题。。。加出来的结果它也是一个左值。 class A { ... }; A a1,a2; ***.operator=(a1+a2); 这一行翻译过来就是,把a2加到a1上,加之前,a1是左值,a2是右值 加完依然是个左值。 还有 加之前a1是左值,a2就是右值呢?why? ……
你去查PRIMER吧。。。左值是可以拿来当右值使用的,就像非const的对象可以被作为一个参数传入一个被限定为const的函数里。UNDERSTAND? 简单的说就是a1是个左值,a2也是个左值。你可以把左值理解为,可以被改变的值。只不过这一步a2没有被改变,它被进行了一次“不改变”的操作。一个可以被改变的东西,当然可以被拿来进行一次不被改变的操作。反之就不行了,一个不可以被改变的东西,是一定不能被拿来进行一次“可以改变其值”的操作(int abc(AAA& lhs))。建议你去好好的看看基础的书,而不是在这里发问。
Lionheartch 2013-04-11
  • 打赏
  • 举报
回复
引用 28 楼 yudahai109 的回复:
引用 26 楼 u_1_n_2_i_3 的回复:引用 21 楼 vipxuliang 的回复:引用 19 楼 u_1_n_2_i_3 的回复:so easy 的问题。。。加出来的结果它也是一个左值。 class A { ... }; A a1,a2; ***.operator=(a1+a2); 这一行翻译过来就是,把a2加到a1上,加之前,a1是左值,a2……
感谢指导~
Lionheartch 2013-04-11
  • 打赏
  • 举报
回复
引用 29 楼 u_1_n_2_i_3 的回复:
是的,也会多析构一次的。返回的还是一个临时对象,不过不是原来这个对象。原来的对象是在函数内的栈上的空间,这个返回的我就不知道在哪段空间了,理论上应该是在调用函数的栈空间里,我没跟汇编码。
感谢指导~
_uniqs 2013-04-11
  • 打赏
  • 举报
回复
是的,也会多析构一次的。返回的还是一个临时对象,不过不是原来这个对象。原来的对象是在函数内的栈上的空间,这个返回的我就不知道在哪段空间了,理论上应该是在调用函数的栈空间里,我没跟汇编码。
有新工作否 2013-04-11
  • 打赏
  • 举报
回复
引用 26 楼 u_1_n_2_i_3 的回复:
引用 21 楼 vipxuliang 的回复:引用 19 楼 u_1_n_2_i_3 的回复:so easy 的问题。。。加出来的结果它也是一个左值。 class A { ... }; A a1,a2; ***.operator=(a1+a2); 这一行翻译过来就是,把a2加到a1上,加之前,a1是左值,a2是右值 加完依然是个左值。 或者你可以写一个函……
这个你说错了,operator+以后,在里面创建的对象已经消失了,返回的是一个值。这时候调用 复制构造函数 新建了一个对象,这个对象再被 operator=调用的! 不信你运行一下试试,这边多一个 复制构造函数 创建的对象的
铁文 2013-04-10
  • 打赏
  • 举报
回复
对于基本数据类型而言,intA+intB的结果必须作为prvalue,因为(intA+intB) = 10这样的写法毫无意义。 对于对象来说,并不存在原生的obj1+obj2之类的操作;而为了让他们合法可行,我们必须定义operator+(成员或者非成员)。那么,CObj CObj::operator+(const CObj& b)和CObj CObj::Add(const CObj& b)之间有什么不同吗?编译器是否需要将他们区别对待呢?从实际情况来看(至少在VC上)似乎没有。那么问题可以转化为,函数的返回值可以作为左值使用吗?显然是可以的,比如: int& CObj::GetRef(){return m_Data;} obj.GetRef() = 1; 好吧,这只是一个玩笑。 还是来看看CObj CObj::Add(const CObj& b): CObj CObj::Add(const CObj& b) { CObj obj; ... return obj; } 此处可以问各位一个问题,对于下面的代码断,CObj的析构被执行了几次? { CObj obj1,obj2; obj1.Add(obj2); } 如果改成下面这样,CObj的析构又被执行了几次? { CObj obj1,obj2; CObj obj3 = obj1.Add(obj2); } 看看标准对CObj CObj::Add(const CObj& b)是怎么说的: CObj CObj::Add(const CObj& b) { CObj obj;//这只是一个很普通的局部变量,左值右值都可以 ... return obj;//执行完后,obj就被析构了,可在CObj obj3 = obj1.Add(obj2);之后,obj3的内容正确无误,这是因为,真正被返回的是obj的一个副本,我们看不见摸不着,象幽灵一样,这个副本被称作临时对象 } An rvalue is an xvalue, a temporary object or subobject thereof, or a value that is not associated with an object. The result of calling a function whose return type is not a reference is a prvalue. 没错,是右值,而且还是纯右值。 所以,只能说,lz使用的编译器没按照标准来
Lionheartch 2013-04-09
  • 打赏
  • 举报
回复
引用 14 楼 yudahai109 的回复:
运行到overload=就停止了
大哥,能输出overload =说明已经被重载了。出错是showit()里pmessage指向不可知内容才出错的啊。我用的也是vs2010.
有新工作否 2013-04-09
  • 打赏
  • 举报
回复
运行到overload=就停止了
有新工作否 2013-04-09
  • 打赏
  • 举报
回复
没有被重载吧,出错了,怎么会被重载呢?你用的什么编译器呀?我用的vs2010
有新工作否 2013-04-09
  • 打赏
  • 举报
回复
本来就被重载了呀,text1+text2以后,返回的是一个临时对象,这个临时对象被 复制构造函数 构造成一个新的对象,直接被 text3.operator=()调用,并且调用的是其引用!
Lionheartch 2013-04-09
  • 打赏
  • 举报
回复
引用 9 楼 yudahai109 的回复:
没有错呀,你在operator+里面建了一个message,对应的,在overload+下面有一个instructor,这就是你的message构造函数。 然后返回message的 值,这边要记住,不是返回 message 的引用,而是值。所以在instructor下面调用了 复制构造函数,创建了一个新的对象,再被 引用 到operator=的参数里面! ……
改成Cmessage&后报错报的是在
text3.showit()
text3.operator=()
依然被重载了,继续求教~
有新工作否 2013-04-09
  • 打赏
  • 举报
回复
如果你在operator+的返回值,返回 引用,即返回 Cmessage&,我想就应该报错了。
有新工作否 2013-04-09
  • 打赏
  • 举报
回复
没有错呀,你在operator+里面建了一个message,对应的,在overload+下面有一个instructor,这就是你的message构造函数。 然后返回message的 值,这边要记住,不是返回 message 的引用,而是值。所以在instructor下面调用了 复制构造函数,创建了一个新的对象,再被 引用 到operator=的参数里面!
Lionheartch 2013-04-09
  • 打赏
  • 举报
回复
引用 19 楼 u_1_n_2_i_3 的回复:
so easy 的问题。。。加出来的结果它也是一个左值。 class A { ... }; A a1,a2; ***.operator=(a1+a2); 这一行翻译过来就是,把a2加到a1上,加之前,a1是左值,a2是右值 加完依然是个左值。
还有 加之前a1是左值,a2就是右值呢?why?
Lionheartch 2013-04-09
  • 打赏
  • 举报
回复
引用 19 楼 u_1_n_2_i_3 的回复:
so easy 的问题。。。加出来的结果它也是一个左值。 class A { ... }; A a1,a2; ***.operator=(a1+a2); 这一行翻译过来就是,把a2加到a1上,加之前,a1是左值,a2是右值 加完依然是个左值。 或者你可以写一个函数 abc(A& rhs); 里面是可以改变rhs的值的。 所以你仔细看看c++……
那为什么这样就不可以呢?
#include<iostream>
using namespace std;
int fun1(int& sum)
{
	cout<<"rvalue"<<sum<<endl;
	return 0;
}
int main()
{
	int sum = 0;
	int a = 1;
	int b = 1;
	fun1(a+b);
	return 0;
}
有新工作否 2013-04-09
  • 打赏
  • 举报
回复
这样,你在cout<<"overload="<<endl;的上面加一条cout<<pmessage<<endl;看看还能不能运行到overload=。 这样不就知道有没有构造出 text3了么!
_uniqs 2013-04-09
  • 打赏
  • 举报
回复
so easy 的问题。。。加出来的结果它也是一个左值。 class A { ... }; A a1,a2; ***.operator=(a1+a2); 这一行翻译过来就是,把a2加到a1上,加之前,a1是左值,a2是右值 加完依然是个左值。 或者你可以写一个函数 abc(A& rhs); 里面是可以改变rhs的值的。 所以你仔细看看c++primer 里面operator=的参数都是加了const限定的。
加载更多回复(11)

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧