注册 登录
编程论坛 C++教室

[求助]++a++与(++a)++

ioriliao 发布于 2007-06-15 11:18, 2343 次点击
++a++这样不行,为什么(++a)++ 行呢?
谢谢.
46 回复
#2
HJin2007-06-15 11:33

1. a++ returns a const obj
++a returns a reference.

see the following code --- how to overload ++ and -- in C++.

2. ++a++ does not work since your complier interprets it as

++( (a++) )

Since a++ is a const obj, say b, ++b must not be allowed;


editted away since it is very hard to understand.

[此贴子已经被作者于2007-6-15 11:46:56编辑过]

#3
ioriliao2007-06-15 11:38
仁兄,你的程序我看不明白,我希望简单点.
#4
anthony6342007-06-15 11:53
从左向右尽可能多地把连续的+号组成运算符。所以把自己搞糊涂了
#5
ioriliao2007-06-15 12:24
以下是引用HJin在2007-6-15 11:33:01的发言:

1. a++ returns a const obj
++a returns a reference.

see the following code --- how to overload ++ and -- in C++.

2. ++a++ does not work since your complier interprets it as

++( (a++) )

Since a++ is a const obj, say b, ++b must not be allowed;


editted away since it is very hard to understand.

仁兄的意思是++a 返回的变量,a++返回的是常量是不,但为什么会有这种区别的,两者都是自增运算符,为什么会有这种区别?

#6
yuyunliuhen2007-06-15 12:49
#7
aipb20072007-06-15 12:52
我觉得这要看编译器是怎么解析的,
前自增和后自增的优先级一样,如果先前自增的话,我觉得上面那个可以!
如果先后自增的话,就不对了!

不知道对不!
#8
aipb20072007-06-15 13:07
++a return (a+1)
a++ return (b=a,a+1,b)
#9
HJin2007-06-15 13:36

have your ever overloaded the ++ and -- (totally 4 operators) for a class, say A? If you did this, then you understand what I said.

Try to do the following exercise:

[CODE]class A
{
// overload ++(two versions)

private:
int d;
double d;
};[/CODE]

your declaration for the postfix ++ must be

[CODE]const A operator++(int); /// postfix [/CODE]

(here we used a dummy int argument to mark it as the postfix version, otherwise, you cannot
make it different from the prefix version. )

for the prefix version must be
[CODE]A& operator++() /// prefix[/CODE]

All other variants are wrong. You may ask me why this has to be so? I would have to tell you, the writers for the compliers, both MS C++ and g++, implemented it so.

/**
This is an option for the postfix ++. But since it returns void,
we cannot use it in an expression, say (a++) + 1.
*/
//void operator++(int)
//{
// ++(*this);
//}

[此贴子已经被作者于2007-6-15 13:40:56编辑过]

#10
ioriliao2007-06-15 15:02
谢谢各位的帮助,我似乎明白了,我要去做多些测试看看才行!
#11
LoveGood2007-06-15 20:45

请问你们接触VC多久了啊

#12
aipb20072007-06-15 21:13
以下是引用LoveGood在2007-6-15 20:45:24的发言:

请问你们接触VC多久了啊

有人在说VC吗?

#13
yuyunliuhen2007-06-15 21:58
#14
slv3092007-06-15 22:01
2楼的大侠貌似是这个意思:

++a++就相当于++((a++)), a++返回的相当于一个常量,const类型,我们称它为b,那么++a++就等于++b,而常量是不允许被写作++b的。。。

理解错的请指正,谢谢~
#15
I喜欢c2007-06-15 22:53


为什么到处都能看见讨论这问题..



我觉得没什么意思呢?写程序一般不会用..
自找麻烦呀?
#16
ioriliao2007-06-16 00:03
以下是引用I喜欢c在2007-6-15 22:53:25的发言:


为什么到处都能看见讨论这问题..



我觉得没什么意思呢?写程序一般不会用..
自找麻烦呀?

我不知道别人讨论这个问题是为了什么,但我是为了搞明白一门语言的本质,我的最终目标是希望有能力写一个编译器,
所以对语言的本质就想了解得透切些!

#17
aipb20072007-06-16 01:38
回复:(ioriliao)以下是引用I喜欢c在2007-6-15 22:...
强!
#18
I喜欢c2007-06-16 10:22
有能力写一个编译器??

哦.. 目标不同.. fighting........
#19
ioriliao2007-06-16 13:11
呵呵,要写一个编译器的能力我还差很远很远,但我的目标是这样的!
你的目标是什么呢?
#20
野比2007-06-16 14:54

写编译器也没必要搞懂C++的本质啊...C++不过是个工具..
词法分析,语义分析才是最难的...


记得看一个老外的书写的, 为了程序里避免错误, 应该尽量使用前缀++, 他还很幽默的说"C++其实应该把名字改成++C才对"....

#21
ioriliao2007-06-16 16:01

我想一开始得模仿一下别人的编译器吧,所以得弄明白一门程序的本质!

#22
野比2007-06-16 16:16
回复:(ioriliao)我想一开始得模仿一下别人的编译器...

哦.. 也不失为一种方法
送你一份简单词法分析源代码作为参考. 应该对你写编译器有帮助..

只有本站会员才能查看附件,请 登录

#23
ioriliao2007-06-16 16:51
非常感谢你!
#24
I喜欢c2007-06-16 16:54
以下是引用ioriliao在2007-6-16 13:11:17的发言:
呵呵,要写一个编译器的能力我还差很远很远,但我的目标是这样的!
你的目标是什么呢?

哎.. 没有目标..

我也不是干这行的..

个人爱好,写这耍..呵呵

#25
aipb20072007-06-16 16:58
以下是引用HJin在2007-6-15 13:36:29的发言:

have your ever overloaded the ++ and -- (totally 4 operators) for a class, say A? If you did this, then you understand what I said.

Try to do the following exercise:

[CODE]class A
{
// overload ++(two versions)

private:
int d;
double d;
};[/CODE]

your declaration for the postfix ++ must be

[CODE]const A operator++(int); /// postfix [/CODE]

(here we used a dummy int argument to mark it as the postfix version, otherwise, you cannot
make it different from the prefix version. )

for the prefix version must be
[CODE]A& operator++() /// prefix[/CODE]

All other variants are wrong. You may ask me why this has to be so? I would have to tell you, the writers for the compliers, both MS C++ and g++, implemented it so.

/**
This is an option for the postfix ++. But since it returns void,
we cannot use it in an expression, say (a++) + 1.
*/
//void operator++(int)
//{
// ++(*this);
//}


看了下你的解释,我想说点看法:

首先,我不明白你为什么把后自增的返回值认为是一个常量?你在说明++重载的时候
const A operator++(int);
我也写过++重载,但是我从来都
A& operator++();
A operator++(int);
所以,我认为问题关键不在这里,并且由此又引出一个问题,内置类型和类类型对++的理解。
想起以前一个帖子:(yuyunliuhen 斑竹连接出来那个)

在那个问题里,大家都说清楚了前自增,后自增的区别。
前自增返回变量本身,后自增返回临时变量。
但是我想即使是临时变量,也应该可以取地址的啊。
比如 int b = a++;
然后 &b 是允许的吧!
所以这点并不足以解释。如果用HJun的返回常量理论,也一样有这个问题。

我用类重载++时,
++a++ //== ++(a++)这样用是可以的。


所以我觉得,内置类型中++的实现不同与类类型中++重载。
至于,再深一步的,就看大家了!

ps:不对的请指教,刚才写段小代码突然想到了。

[此贴子已经被作者于2007-6-16 16:59:41编辑过]

#26
ioriliao2007-06-16 17:29
以下是引用I喜欢c在2007-6-16 16:54:00的发言:

哎.. 没有目标..

我也不是干这行的..

个人爱好,写这耍..呵呵

我觉得你有一种怀才不遇的感慨!

#27
ioriliao2007-06-16 18:00

a++是否等价于a=a+1
我写了一段代码
int a=10;
int* p;
p=&(a=a+1); //这是返回变量 ,可为什么a++就返回常量呢?编译器究竟是怎么样拆开来的?
这样编译通过
如果两者等价可为什么
p=&(a++) //就不行

++a拆开来等价于什么?

#28
yp4562007-06-16 18:30
15楼的观点强烈支持,实用点吧~~~难道自己写程序也这么用?存心锻炼自己的思维能力?

[此贴子已经被作者于2007-6-16 18:30:42编辑过]


#29
ioriliao2007-06-16 18:56
以下是引用yp456在2007-6-16 18:30:21的发言:
15楼的观点强烈支持,实用点吧~~~难道自己写程序也这么用?存心锻炼自己的思维能力?

我知道你所谓实用点.不外是写写erp如此之类的.如果所谓实用点,我根本用不着来学习C++,我去学.net就行了.
我已经说得很明白了,我想知道的是一些本质的东西.当你在用一个按钮时,可曾想过
这个按钮是怎么来的.你又何曾想过.net是如何来的.C++又是如何来的.我就是不想知其然,不知其所以然.
或者我只能对你说,道不同不相为谋.

#30
I喜欢c2007-06-17 10:29
以下是引用ioriliao在2007-6-16 17:29:27的发言:

我觉得你有一种怀才不遇的感慨!

哎.. 有那本事就好了..

菜鸟一只...

#31
I喜欢c2007-06-17 10:31
以下是引用ioriliao在2007-6-16 18:00:00的发言:

a++是否等价于a=a+1
我写了一段代码
int a=10;
int* p;
p=&(a=a+1); //这是返回变量 ,可为什么a++就返回常量呢?编译器究竟是怎么样拆开来的?
这样编译通过
如果两者等价可为什么
p=&(a++) //就不行

++a拆开来等价于什么? 我认为++a 才等价与a=a+1;

#32
I喜欢c2007-06-17 10:39

按照前面所说:

a++返回的是常量,那么 &(常量)就是一个错误的操作,所以答案就很明确了..
不知道 ioriliao 这下清楚了没?

#33
ioriliao2007-06-17 11:35

我知道这是返回常量,我却不明白为何会返回常量,而++a却不是!

#34
百年不亮2007-06-17 11:48

yuyunliuhen 在6楼的回复中给出了我以前的帖子的地址,估计楼主根本没看.


我以前写了个帖子讨论C++内置类型的++前缀和后缀.我想自定义的对象++前缀和后缀很明确,大家都知道,谈论内置类型的却不多.在C++中内置类型++前缀返回原始变量,后缀返回临时变量,C++不允许对临时变量进行操作,因为有的编译器在实现临时变量时使用寄存器变量,显然对寄存器变量取地址是非法的.C和C++在这个问题上有一个区别,在C中++前缀也是rvalue,使用&(++a)会提示&需要一个lvalue.

下面我把之前哪个帖子贴过来:
https://bbs.bc-cn.net/viewthread.php?tid=140728


[QUOTE]
之前的一个帖子中提到关于自增前缀和后缀的问题,帖子在这里:https://bbs.bc-cn.net/dispbbs.asp?boardid=56&replyid=58792&id=124908&page=20&skin=0&star=1
int main()
{
int x=5;
int *p=&++x;
int *q=&x++; //error C2102: '&' requires l-value
return 0;
}

Cpp1.cpp
C:\Documents and Settings\Administrator\桌面\daima\Cpp1.cpp(6) : error C2102: '&' requires l-value


最后大家争论的焦点就在为什么&++x合法,而&x++会出错,有人提到我们在c++中重载前缀自增时直接将原始对象加一,最后返回原始对象的引用,所以&++x取的是原始对象的地址,是合法的。而在后缀的实现中是通过将原始对象的值赋给一个临时对象,再将原始对象加一,最后返回临时对象的值,&x++就是取一个临时对象的地址,所以是错误的操作。我看后觉得这是有道理的,但是这只是推测,不敢确定c/c++中内置类型也是这样实现的,近来翻看Bjarne Stroustrup 的 <<The C++ Programming Language>>,发现有一段话如下:

6.2.5 Increment and Decrement
The ++ operator is used to express incrementing directly,rather than expressing it indirectly using a combination of an addition and an assignment. By definition, ++lvaue means lvalue+=1, which again means lvalue=lvalue+1 provided lvalue has no side effects. The expression denoting the object to be incremented is evalued once(ovly). Decrementint is similarly expressed by the -- operator. The operators ++ and -- can be used as both prefix and postfix operators.The value of ++x is the new(that is, incremented)value of x. For example, y=++x is equivalent to y=(x+=1). The value of x++, however, is the old value of x. For example, y=x++ is equivalent to y=(t=x,x+=1,t), where t is a variable of the same type as x.

最后两句话就是我关心的:x++的值是x自增之前的旧值。例如y=x++相当于y=(t=x,x+=1,t),其中t是和x相同类型的变量

对比y=++x is equivalent to y=(x+=1) 和 y=x++ is equivalent to y=(t=x,x+=1,t),可以看出前缀和后缀的本质差别,&++x等价于&(x+=1)即(x+=1,&x); &x++等价于&(t=x,x+=1,t)即&t.

有了Bjarne Stroustrup他老人家的话自己终于放心了。
[/QUOTE]
#35
ioriliao2007-06-17 11:53
首先我要说声谢谢!
其实我是看了的,只
是心中还是有疑惑 :

&t 和是常量还是变量?
&t 何以见得会错误?
#36
I喜欢c2007-06-17 11:58
这的 t 只是寄存器中一个临时变量(我认为) 所以.....

其实不应该是t,而就是一空间,这只是为了说明这个问题才引用 t 说法吧...

[此贴子已经被作者于2007-6-17 12:00:22编辑过]

#37
ioriliao2007-06-17 12:06

这的 t 只是寄存器中一个临时变量
变量不是可以 &t的么,只是常量不行,
这里好像有矛盾,我就是因为这而迷惑了.

#38
百年不亮2007-06-17 12:06
[QUOTE]我以前写了个帖子讨论C++内置类型的++前缀和后缀.我想自定义的对象++前缀和后缀很明确,大家都知道,谈论内置类型的却不多.在C++中内置类型++前缀返回原始变量,后缀返回临时变量,C++不允许对临时变量进行操作,因为有的编译器在实现临时变量时使用寄存器变量,显然对寄存器变量取地址是非法的.C和C++在这个问题上有一个区别,在C中++前缀也是rvalue,使用&(++a)会提示&需要一个lvalue.
[/QUOTE]

你这次可能没有看我的第一段文字,注意我红色部分.

你自己写个测试的短程序,用不同的编译器编译后看看汇编代码,找到临时变量的实现指令.你既然有自己写编译器的志向就应该研究汇编代码,这里没有任何迷雾,真相就摆在你面前.汇编之后了无秘密.
#39
ioriliao2007-06-17 12:11

那么如果我研究C++本身的问题就得连汇编一起上了.谢谢!

#40
aipb20072007-06-17 12:45


你们有的说c++返回常量,有的说返回临时变量,到底是哪个?

还有,看看我的问题好不?25楼!

谢谢!
#41
ioriliao2007-06-17 12:51

呵呵,,又引申出问题了!

#42
jiaju1112007-06-17 22:35

支持楼主的学习方法

我也是这么学的

要学就学精

#43
百年不亮2007-06-17 23:52
好吧,现在讨论aipb2007 的问题

我认为这不是什么返回常量的问题,也没见哪本书说返回常量,再说即使是常量也可以取地址操作,比如:
[CODE]char *p_str="hello";
const int a;
int *p_int=&a;[/CODE]
这里"hello"和a都是常量,也允许取地址.所以还是我说的返回临时变量问题.

至于为什么返回的临时变量不能取地址操作,这是因为临时变量在返回后就不再需要了,所以编译器在实现时可能将临时变量放在堆栈寄存器中(对于一个int型变量编译器有足够的理由放到EAX这样的通用寄存器中),临时变量在返回后编译器会加入代码销毁临时变量,调用临时对象的destructor,如果允许程序用指针指过去,销毁后再用指针访问这段内存很可能出错,如果临时变量在寄存器中就更加不可能让程序员取地址操作了.综上所述,c++不能让程序员对临时变量取地址.

[此贴子已经被作者于2007-6-17 23:54:31编辑过]

#44
aipb20072007-06-18 09:24
回复:(百年不亮)好吧,现在讨论aipb2007 的问题我认...

谢谢!还有点疑惑,就算是临时变量,那怎么又可以进行解引用操作呢?

并且我发先,产生错误的操作是因为程序想修改a++返回的值,比如我可以 (a++)+1,*a++,这些都是允许的。
以你的说法,好象有点矛盾,也不知道是不是我理解错你意思了。
还有,你说“如果允许程序用指针指过去,销毁后再用指针访问这段内存很可能出错”
但是
int a[] = {10,100};
int *pi = a;
int *pi2 = pi++;
cout << &pi2 << endl;

没有错误。说明pi2可以保存pi++返回的临时值啊!
顺便,请教一下,这个 临时变量 怎么用代码实现,我们写函数可以有这样的返回吗?


我也想一次弄清楚,麻烦你耐心点哦!
呵呵呵~

#45
yuyunliuhen2007-06-18 10:31
回复:(百年不亮)好吧,现在讨论aipb2007 的问题我认...
返回值可以是常量,
当返回值为临时变量的时候,临时变量会自动定为常量------------《thinking in C++》
https://bbs.bc-cn.net/viewthread.php?tid=140728
上次说到重载的时候,我们一般会选择让前缀版本的返回值为非常量的,而后缀版本为常量的
#46
aipb20072007-06-18 14:07
还是没解决问题!
#47
百年不亮2007-06-18 14:56
以下是引用aipb2007在2007-6-18 9:24:46的发言:

谢谢!还有点疑惑,就算是临时变量,那怎么又可以进行解引用操作呢?

并且我发先,产生错误的操作是因为程序想修改a++返回的值,比如我可以 (a++)+1,*a++,这些都是允许的。
以你的说法,好象有点矛盾,也不知道是不是我理解错你意思了。
还有,你说“如果允许程序用指针指过去,销毁后再用指针访问这段内存很可能出错”
但是
int a[] = {10,100};
int *pi = a;
int *pi2 = pi++;
cout << &pi2 << endl;

没有错误。说明pi2可以保存pi++返回的临时值啊!
顺便,请教一下,这个 临时变量 怎么用代码实现,我们写函数可以有这样的返回吗?


我也想一次弄清楚,麻烦你耐心点哦!
呵呵呵~

这里的pi++返回了一个临时对象,但是pi2=pi++只是接受了临时变量的值,并没有用指针指向临时变量.你要注意这里哪个是临时变量.我强调的是不能用指针指向临时对象,而接受临时对象的值完全是正常操作.你举的例子是接受临时对象的值.

还是43楼我说的临时对象在返回之后会编译器会调用destructor销毁临时变量,所以不能取临时变量地址.
我觉得你还是没有明白接受了临时变量的值 取临时变量地址 的区别,临时变量名字中临时的就是它的生命周期短,在返回后就结束了,你还要看清楚什么时候创建,什么时候结束这个问题.

1