指向类成员函数指针的问题

时间:2022-08-30 09:43:35
下面这个程序使用函数指针指向类A的成员函数fc,编译有误,不知道有什么语法错误?
#include<iostream>
#include<conio.h>
using namespace std;

class A
{public:int fc(void);
 
 private:int a;};  
   
int main()
{int (A::*f)(void);

 A x;
 x.fc();
 f=A::fc;
 (x.f)();
 
 getch();
 return 0;}


int A::fc(void)
{cout<<"a="<<a<<endl;
    a+=5;
 cout<<"a="<<a<<endl;}

 

73 个解决方案

#1


(x.f)();
改为
(x.*f)();

#2


还是不行,它提示:
invalid use of non-static member function `int A::fc()' 
cannot convert `int (A::)()' to `int (A::*)()' in assignment 

我用的是dev c++

#3


#include<iostream>
#include<conio.h>
using namespace std;

class A
{public:int fc(void);
 
 private:int a;};  
   
int main()
{int (A::*f)(void);

 A x;
 x.fc();
 f=&A::fc;
 (x.*f)();
 
 getch();
 return 0;}


int A::fc(void)
{cout<<"a="<<a<<endl;
    a+=5;
 cout<<"a="<<a<<endl;}

#4


f=A::fc;
改成
f=&A::fc;
我用的g++

#5


哦,对,是的,一定要那样的。
刚刚用VC试,改了两种,结果回复楼主的时候,忘了前边的人,就只写了后边一处,呵呵。

#6


f=&A::fc;

DEV 通过并正常运行

#7


靠,怎么打错了那么多字。。。。。

刚刚用VC试,改了两处,结果回复楼主的时候,忘了前边的了,……

#8


0790,分都给我吧:)

#9


那为什么一般的函数又不用取地址&呢?
void fun()
{...}
void (*pf)();
pf = fun;

pf = &fun
都是对的

#10


恩,我也有这个疑问,希望高手解答一下,谢谢~~~

#11


在C++语言中,对于一个由类名加俩冒号再加成员名构成的东西(学名叫“quilified-id”),比如:A::x,只有当x是A类的静态成员的时候,A::x才能表示一个左值。

而对于函数类型到函数指针类型的默认转换,只有当函数类型是左值的时候才行。所有对于非静态的成员函数,就不存在这种从函数类型到函数指针类型的默认转换,于是编译器也就不知道这个
p = A::f
该怎么搞了。

#12


其实静态的成员就是global的,所以与普通的函数有相同的地位。但为什么非静态函数就不行,就算它的调用方式__thiscall与全局函数的__cdecl是不同的,但它的函数地址难道不也是确定的吗,那编译器为什么不知道怎么处理呢?还有,函数类型的左值是什么概念?

#13


学到了,我原先也有这个疑问

#14


To: blue_zyb()
我前面的回复只是基于C++标准中的一些规则的推理而已。换句话说,从C++标准的规定中,可以非常容易地推出对于楼主的问题,那个“&”是绝对不能省略的。但至于C++语言为何这样设计,我目前的理解也很有限。:P

对于这个问题我个人理解只有以下这些,不一定正确:
(1)要说函数地址确定不确定,由于非静态成员函数指针可以有多态行为,因此,至少在编译期,其地址还真的无法确定。
(2)虽然所有的编译器都肯定会把类的非静态成员函数的代码只生成一份(不管是编译时还是运行时),这一点跟非静态成员变量不一样,变量每个对象都有独立的一份。——但我认为,这依然是编译器的实现细节而已,而不是语言特性。从抽象的语言特性角度讲,非静态的成员函数跟非静态的成员变量一样,在没有对象实例的时候,是形不成左值的。

最后,关于全局或静态函数类型为什么是“左值”,我也不是很理解。:P。我目前倒是觉得全局和静态函数名跟数组名差不多,应该只是个右值才对。但C++标准上的确是那样赫然写着的。:(
不过我每次联想到Windows平台上在使用LoadLibrary把一个模块加载到内存后,“竟然”可以GetProcAddress,我就觉得函数和数组还真的不大一样——既然可以找到它,那么除了有一个地方存着它之外,还有别的解释吗?理论上一个黑客完全可以通过修改内存把一个函数的入口地址改掉,让你找不到。其效果就像那种通过技巧修改常量差不多(注意const修饰的常量也是左值)。
可能思路有些混乱了,期待高手出现。

#15


学到了,谢谢steedhorse(晨星) ,希望能有高手继续出现来讨论这个问题~~~~~

#16


对于steedhorse(晨星)上面的论述,我也发表一点自己的看法,也不一定正确 :)
(1)要说函数地址确定不确定,由于非静态成员函数指针可以有多态行为,因此,至少在编译期,其地址还真的无法确定。

    对于函数的多态行为,虽然是在运行时,根据基类所指的具体对象所包含的虚函数表来找到对应的函数地址,但这个地址难道不是在编译时确定的吗,否则编译器是根据什么填好这个虚函数表的呢?并且,多态行为是与对象指针挂钩的,这里用的是类作用域,需要考虑多态吗?何况楼主的例子中也没有用到多态。
////////////////////////////////////

(2)从抽象的语言特性角度讲,非静态的成员函数跟非静态的成员变量一样,在没有对象实例的时候,是形不成左值的。

     但从具体实现来讲,非静态的成员变量是包含在对象内部的,为一个对象分配空间,它的成员才能分配到相应的存储空间。但毕竟函数是独立于对象之外的,它应该占有自己独立的代码空间。所谓左值,就是代表一块编译时分配好的存储空间。所以,成员变量需要依赖对象而存在,成员函数就没有必要了吧。

/////////////////////////////////////////////
最后,关于全局或静态函数类型为什么是“左值”,我也不是很理解。:P。我目前倒是觉得全局和静态函数名跟数组名差不多,应该只是个右值才对。

函数类型是一个左值,我的理解正如前面所说,左值意味着编译时分配好的一块存储空间。那么对于函数来说,函数对应了一段代码,这段代码所占空间的整体构成了这块存储空间,而函数名用来引用这块空间。这就好像int a;为a分配的那4个字节构成了存储空间,而a这个名字用来引用这4个字节的空间。只是a的值被解释为integer,而函数名被解释成什么呢?你不能说函数名的值是哪一大堆二进制的代码值吧,所以函数名被解释成函数代码的起始地址。而类似&fun的写法,则表示取函数所占存储空间的地址,也是函数的首地址。

数组名其实也是一个左值,an arrayname is an l-value but not a modifable l-value(Expert C)。所以也许,函数名也是一个not modifable l-value.

///////////////////////////////////////////////////////////////
(注意const修饰的常量也是左值)
C++中,除了*分配存储空间的情形外(比如对const取地址和extern const),编译器是不必为const分配存储的。也就是说在没有为const分配存储空间的情形下,编译器会在compile time进行常量折叠,这时的const就不构成一个左值。

#17


//所以,成员变量需要依赖对象而存在,成员函数就没有必要了吧。
——你好象还是没有区分开编译器的实现细节和语言的语法特性,从理论上讲,我为每一个对象都生成一份成员函数的代码,虽然效率非常非常非常低,但你不能说我“错”,丝毫没有错,也仍然可以实现C++语言的所有功能。

//编译器会在compile time进行常量折叠,这时的const就不构成一个左值。
——这个也是概念问题,是不是左值,只跟语言语法的定义有关,跟编译器的实现及优化毫无关系。在特殊的情况下,非const量也照样可以被编译器优化掉(比如定义了但没有使用的变量),但它仍然是左值。原因就是“左值/右值”是个语法概念,没有这个概念就难于描述一种编程语言。但它跟实际的编译器实现并没有什么直接关系。概念而已,没啥实际的道理可讲,C++标准就是这样规定的:一切const量都是左值——优不优化是编译器的事,语言不管。

#18


呵呵,我确实没有研究过C++的标准。。。

#19


但是如果写成
f=A::fc;
(x.*f)();
在vc6.0下一样可以通过编译的阿
  那steedhorse(晨星) 所说的  那个“&”是绝对不能省略的  是不是就有点。。。。

#20


还真的来。。。。
不仅VC6,连VC2003也过了。
无语了,微软的东西总是能让人震撼。。。。

#21


To:steedhorse(晨星)
我手头有C++标准,"一切const量都是左值"这一句在什么位置?

#22


精彩!收藏!

#23


看来关于const量是否左值这个问题上,我犯错误了。
以前曾就这个问题跟一个对C语言标准非常熟悉的朋友讨论过,后来就一直想当然的那么理解了。关于const量的左右值这个问题,我就自己没有找到第一手证据就妄作分析可能对别人造成的误导道歉。

不过我现在也不敢说它“有时可能不是左值”,我想进一步确认一下这个问题。虽然这个问题是后面不小心引出来的,但希望楼主先不要结帖,再听听别人对这个问题的意见。:P

至于楼主的问题本身,C++标准的原文如下
ISO/IEC 14882 Second edition 2003-10-15 5.3.1.3

A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed in parentheses. [Note: that is, the expression &(qualified-id), where the qualified-id is enclosed in parentheses, does not form an expression of type “pointer to member.” Neither does qualified-id, because there is no implicit conversion from a qualified-id for a nonstatic member function to the type “pointer to member function” as there is from an lvalue of function type to the type “pointer to function” (4.3). Nor is &unqualified-id a pointer to member, even within the scope of the unqualified-id’s class. ]

#24


const qualified obj是lvalue的证据刚刚在C99的6.3.2.1找到了
A modifiable lvalue is an lvalue that does not have arry type, does not have an incomplete type, does not have a CONST-qualified type, ...

#25


谢谢cber大侠,呵呵。很少看到您老人家关注技术帖子了。:P

const修饰的常量的确是左值,是个"unmodifiable lvalue"。
虽然C++标准(ISO/IEC 14882 Second edition 2003)中的说的不像C语言标准里那么直接明了(这是不是好些对C更熟悉的的朋友更清楚这个问题的原因?),但还是可以找到证据:
(1)首先,3.9.3节详细地介绍了cv-qualifier,讲解了cv-qualified type定义的object和与其对应的cv-unqualified类型对象的联系。尤其这句:The presence of a const specifier in a decl-specifier-seq declares an object of const-qualified object type; such object is called a const object.
(2)然后,紧接着在3.10节的第二款,就给lvalue下了个定义:An lvalue refers to an object or function. Some rvalue expressions—those of class or cv-qualified class type—also refer to objects.
(3)从第三节往后,就是一些具体的说明或特殊情况的说明,包括一些虽然也引用对象,但却不是左值的情况。但所有这些特殊情况的中,没有再提倒cv-qualified type定义的const object,换句话说,const object作为一个object,除了是左值,已经没有需要补充的了。
(4)注意第9款说的“Class rvalues can have cv-qualified types;”仅仅是对第2款后半句的进一步解释,而关于这种“class rvalue”所指代的东西,在针对第二款的脚注47中已经有个说明:Expressions such as invocations of constructors and of functions that return a class type refer to objects, and the implementation can invoke a member function upon such objects, but the expressions are not lvalues.即函数调用和构造函数能产生class类型的对象,而且也可以在这些对象上调用成员函数,但作为一个表达式,它只有右值。
(5)第13,14款再次强调了modifiable的问题,我认为这是针对const type的。除了const type外,我想不出还有几种“nonmodifiable lvalue”了。

所以,const修饰符所定义的对象就是一种“unmodifiable lvalue”。

当然,这样理解太累了,关于const type对象是左值,有两个最好的佐证:
(1)它可以被取地址(注意“左值”并没有复杂成一个“动态”的概念。“可以”就足以说明问题了,因为C++语言从来不允许对右值取址)。
(2)它可以被引用。
所以,只要在程序中看到:const int M = 12345;这种,就可以说M是个左值了,而不必等到把后续的代码全部审视过,把其它的所有源文件也都检查过,确定没有被取址后,才可以放心大胆地说这是个左值。“左值”这个概念是“静态”的,一种表达式的内在属性而已,没有复杂到此种程度。也没有这种说法:你在另外一个文件里加了一行程序,就把另一个文件的一个右值表达式给变成左值表达式了。

最后,再说说刚才的那句“C++语言从来不允许对右值取址”,或许有朋友要挑刺了:“哈哈,楼主的问题不就是个反例吗?那个A::fc就不是左值,怎么也用了‘&’取址了”。前面只是为了先把那个问题说清楚而偷的一点懒而已,事实上确实不能说“C++语言从来不允许对右值取址”,在5.3.1中,C++标准的原话是:“The result of the unary & operator is a pointer to its operand. The operand shall be an lvalue or a qualifiedid.”,也就是说,“&”做取址运算符时只能作用于左值,或者:qualified-id——也就是A::fc这种东西。

#26


我的理解来自于Thinking in CPP(version 2)的chapter8 Constants. 要从头浏览才能更好的理解,但这里摘几段来说明一下我的理解。

首先要说明的是C和C++中的const是不尽相同的,所以不能用C99标准(C标准)来推断C++中的标准。

#1先摘一段对C++中const的说明:
Normally, the C++ compiler avoids creating storage for a const, but
instead holds the definition in its symbol table. When you use
extern with const, however, you force storage to be allocated (this
is also true for certain other cases, such as taking the address of a
const). Storage must be allocated because extern says “use external
linkage,” which means that several translation units must be able to
refer to the item, which requires it to have storage.
In the ordinary case, when extern is not part of the definition, no
storage is allocated. When the const is used, it is simply folded in at
compile time.
The goal of never allocating storage for a const also fails with
complicated structures. Whenever the compiler must allocate
storage, constant folding is prevented (since there’s no way for the
compiler to know for sure what the value of that storage is – if it
could know that, it wouldn’t need to allocate the storage).

#2下面再摘一段关于C++中const与C中不同之处的说明:
Constants were introduced in early versions of C++ while the
Standard C specification was still being finished. Although the C
committee then decided to include const in C, somehow it came to
mean for them “an ordinary variable that cannot be changed.” In C,
a const always occupies storage and its name is global. The C
compiler cannot treat a const as a compile-time constant. In C, if
you say
const int bufsize = 100;
char buf[bufsize];
you will get an error, even though it seems like a rational thing to
do. Because bufsize occupies storage somewhere, the C compiler
cannot know the value at compile time.

#3最后摘一段Expert C中关于lvalue 和rvlaue的说明:
The compiler allocates an address (or l-value) to each variable. This address is
known at compiletime, and is where the variable will be kept at runtime. In contrast, the value stored in a variable at runtime (its r-value) is not known until runtime. If the value stored in a variable is required, the compiler emits code to read the value from the given address and put it in a register.

其中#3中的说明可以很好的帮助理解#2中最后的一句话。 Because bufsize occupies storage somewhere, the C compiler cannot know the value at compile time.也就是说在C中,const量是一个lvalue,它occupies storage,它的值(r-value)只有到runtime才可以通过编译器emit code来得到。
再看#2种最后一句。Whenever the compiler must allocate
storage, constant folding is prevented (since there’s no way for the
compiler to know for sure what the value of that storage is )。也就是说,当编译器必须allocate storage(lvalue的含义)的时候,constant folding将被阻止。因为这个时候对于这个const所占storage的值(它的rvalue)编译器不能确定的知道。

所以,在C++中,对于const的处理并不就是C中那样的直接就是lvalue,否则,对于下面的代码
const int size = 10;
int array[size];
就无法成立,因为array定义中用到了size的值,如果size成为了一个lvalue,分配了storage,那么它的值就必须让编译器生成mov eax,dword ptr [size] 之类的代码,然后运行时才能得到,但是数组的分配都是在编译时进行的。

PS:个人理解,不一定全对



#27


呵呵,这里是挺搞的。但我觉得
首先,编译器实现说明不了太多的问题。只要不违反语言标准,编译器为提高效率做任何动作都最天经地义的,不管巧妙到何种程度。编译器当然应该做“avoids creating storage for a const”这种事,既使是左值也不能放弃一切可能的优化。其实编译器还可以“避免为未使用的变量分配空间”,但这跟理论上的语言特性关系不大。

然后,C++标准中倒是找不到必须为左值分配运行时存储,而且必须在每一处使用其右值的地方都产生运行时读取代码的规定,相反,C++里对左右值的阐述更抽象,丝毫没提内存分配和代码生成。

最后,如果真的如你所说,不是右值就不能定义数组。那万一在那个定义const的源文件中,先用它定义了个数组,接着又取用了它的地址怎么办?难道让原来的数组定义失效,并产生“不能用运行时左值定义数组”的编译错误吗?

C++标准中对于数组的定义,只从上层的高度提到:bounds必须是constant_expression,而constant_expression可以包含const variables,其它就没说啥了。

不过C++标准为了让这一切不出任何漏洞,倒是很巧妙的“推卸”了责任,说是试图修改const对象的动作,如果不是“ill-formed”,那就是“后果undefined”。——我觉得原因显然是在宣告:它就是准备在编译时取用这个左值的右值,谁要是胆敢干扰这一切后果自负。:)

#28


我觉得C++就是在const的问题上有两手准备,由于const可以作为常量来使用,所以编译器要求
const必须初始化。然后,在编译器实现的内部,它可以把这个值保存在符号表里,而不是像一般的变量那样对待。在需要常量的位置(例如数组定义),它就可以用这个自己保存起来的确定的已初始化的值。至于后面特定情形必须为const分配对应的内存空间,编译器不管,反正我认定我最先看到的const被初始化的值。例如,在VS2005下,
const int size = 10;
cout << size << endl;
int *p = const_cast<int*>(&size);
*p = 11;
cout << size << endl;
上述的代码的输出都是10,也就是说该编译器认定的就是编译时看到size被初始化的那个值(当然也可以说只是VS2005这么做,其实是晨星所说的undefined的行为)。

但我不认为用的就是“这个左值的右值”,因为为左值分配的那个地址是映射到内存中去的,而编译器似乎就是在使用它自己保存在符号表中的值。它直接去取自己数据结构表中的值,而不是到运行时再去取内存中的值。

#29


那说明你还是认为“左值”这个概念至少要涉及运行时的取值。
而我认为事情没有那么复杂,左值就是个左值而已,左它的去吧,只要编译时能确定了值了就不要等到运行时,也不一定真的要分配空间。
但不管怎么说,C++标准不敢说const修饰的量是个右值,那样麻烦就大了。

#30


我发现渐渐的咱们的分析不在C++标准上,而在于“左值”这个概念上了。
你认为“它直接去取自己数据结构表中的值,而不是到运行时再去取内存中的值。”——这就说明不是左值。
而我则感到莫名其妙:为什么这样就一定不是左值了?

#31


因为我按照Expert C中所说,The compiler allocates an address (or l-value) to each variable.In contrast, the value stored in a variable at runtime (its r-value) is not known until runtime. 
所以我认为,如果一个变量名构成了一个左值(也就是说为它分配了存储,并对应了一个地址),那么取它的值(也即右值)就要等到运行时才知道。也就是说,对于最简单的一句
int a ;编译器为a分配了一个地址,然后到程序运行时,把为a分配的地址映射到内存中。a的值(rvalue)只有这时才可以知道(即使在上面的情况下a里面的值是垃圾)。而const的值明显在编译时已经确定。

至于你说的"左值就是个左值而已,只要编译时能确定了值了就不要等到运行时",那你的意思是
有类似int a = 2; int b = a + 1;的代码,编译器能够分析到a的值为2,所以就不必为a分配空间,然后保存a的值赋给b对吗。但是,如果a的定义是cin >> a;你就不能了吧。主要原因就是左值(分配存储)是一种统一的处理模式和概念,你总不能让编译器对这个a的定义进行分析,对那个b的运行时输入分配存储,并发射代码。毕竟,程序干些什么事是程序自己的事,编译器只是保证我的一套翻译模式能够确保程序的运行,你总不能让它帮助你去分析或执行程序的运行吧。

#32


“但是,如果a的定义是cin >> a;你就不能了吧。”
——所以说,左值就是左值,虽然某些特殊的况下某些特殊的编译器可以优化它的存储和访问,但作为一个表达式,它是左值已经由语法决定了。
——我倒觉得,正如你所举的例子,从表面上看,“左值”的最大特点之一就是“不可能在所情况下都被优化没了”——总是存在你无法优化的情况。否则干粹规定它是右值不就得了?一了百了。

#33


或者说,我认为,右值不右值对应的主体是你的程序,而不是编译器,虽然编译器代码运行可以知道int a = 2;中的2这个具体的数值,但是不到你的程序运行,a对应的右值2也是不得而知的。所以,我认为右值就对应了"程序运行时"的概念。

#34


这个不太对吧,字面常量和常量表达式也是右值,比如:
2
365 * 24
"0123456789"[7]
等等。

还有,你刚才举的那个例子在多线程下是不可优化的。单线程下也不太会优化这种,我觉得,可能会优化的是这种:
int a = 5;
int b = a;
//....此后a再也没被用过。

#35


错了错了。
"0123456789"[7]
显然是个右值,差点上了自己的当。-_-#

#36


靠,还是打错了,“显然是个左值”。。。。。
BS自己一把。

#37


你也提到优化的问题,你不是总强调语法概念吗 :)

当然,我所讲的是主要是变量对应的rvalue的问题。虽然2, 365 * 24这些是右值,但除非你写2;265*24;之类的代码,一般这些值你还是希望赋给一个变量的吧。那么对于类似int a = 3 + 4;之类的代码,3 + 4是可以通过“运行”编译器的代码分析到,然后它帮你优化成7,但这个a的对应的7个值不是要到你的程序运行时才能在某个内存位置被赋值,然后访问吗,这个a所对应的右值是相对你的程序来说,不是编译器。

至于你上面说的“显然是个右值”是写错了还是怎么回事,"0123456789"[7] = 'z';这句代码在VC6下编译通过,在VS2005下编译失败,错误信息:l-value specifies const object。我曾经用cout << typeid("0123456789").name() << endl;之类的代码试过,在VC下是char [11],而在VS2005中是char const [11]

#38


感觉严重跑题了,后面看的有点吐血

#39


是被你引导的。:(
呵呵,那一段跟主题无关,掐了,别播。。。

哦,那个可能2005更符合标准吧,看来偶可能也被VC耍了一把,还一直以为是对的呢。不讨论了,呵呵。

其实我也想说左右值的判别不该多去讨论编译器,而这点你也提过了:“右值不右值对应的主体是你的程序,而不是编译器”。

我想那我们的分歧就在于对于:
const int M = 5;
我认为现在就可以说“M”这个表达式是左值;
而你认为未必,还得看看,有可能形不成左值,是这样吧?

如果是这样,那我可能就不知道如何往下说了,我认为左右值是个静态的概念,不存在这种情况——就是你已经完全了解了这个表达式每一个组成部分,却仍然要“再往下看看”,才敢说话。因为左右值是表达式本身的固有属性,跟如何被使用无关。

#40


我也觉得说得有点多,不过还是要补充一下:
VS2005下也是把"123456789"[7] 当作左值啊,只是它说这个左值是被const修饰的罢了。我刚突然想到试一下const int a = 10; a = 11;看一下编译器的错误信息会不会是l-value specifies const object。没想到在VC6.0下是,而在VS2005下是:you cannot assign to a variable that is const。呵呵,是不是想太多了。。。

const int M = 5; 我没有说对于要用到M的表达式例如int arr[M]还要往下看看啊,我的意思是编译器现在不一定为M分配了像一般那样变量的对应到内存的空间,但它已经知道我要把它作为一个常量来对待,况且我已经知道它的初始值了,可以用它的初始值来充当常量的角色。至于,后面的代码强迫我为它分配存储,那是后话了,我不管,我先用我自己符号表里的那个值。

#41


“我的意思是编译器现在不一定为M分配了像一般那样变量的对应到内存的空间,但它已经知道我要把它作为一个常量来对待,至于,后面的代码强迫我为它分配存储,那是后话了,我不管,我先用我自己符号表里的那个值。”
——这些俺都没有反对啊,俺只是说它是个“左值”,除此之外,没有别的意思。:(

#42


假设还没有为const分配程序地址空间中对应的地址(Expert C中说The compiler allocates 的address 就是l-value),那现在它算是编译器地址空间中的左值吧,还不算你的程序的。呵呵,晕啊晕~~

#43


怎么又说到编译啊,运行的上去了。。。。

M,一个const int型的object(这是标准中的术语,不是指类实例的那个“object”)。
当它做为一个表达式的时候到底是左值还是右值,真的有必要考虑那么多吗?:(

#44


左值就一定要有空间吗?
正确的说法是:“左值不可能在任何情况下都没有空间”。

#45


除了讨论的const,找一个左值不一定有空间的例子给我一下

#46


Expert C是说C的,而C的const与C++的const的区别你前面自己又不是没说过。
它们的相同点是都是左值。
不同点是,C里它是有空间的,所有Expert C中可以轻轻松松地说“地址就是左值”——至少它们有直接的联系。

但C++中const量不一定有空间,所以C++标准就不敢这么说了。
而且C++想了想临时变量虽然只是右值,也需要编译器分配空间,就不更敢这么说了。

#47


左值不一定有空间的。。。。。
——这还少啊?优化呗。。。
int i;
//从此后再也不用i,结果被优化掉了。

但i还是左值——因为这是个语言概念,就是不可以说i是右值。

#48


还有,C++中所有的全局函数,静态成员函数类型都是也都是左值,这一点跟C标准的描述也不一样。

#49


左值不一定有空间的。。。。。
——这还少啊?优化呗。。。
int i;
//从此后再也不用i,结果被优化掉了。

但i还是左值——因为这是个语言概念,就是不可以说i是右值。

哪哪哪,又把优化说进来了吧,所以从语言概念上来说这个i是构成左值的。而且上次我看见你在哪里说过左值右值都只是一个表达式的属性之类的话,那怎么就不能说i是右值。只是说i代表了一块存储,那既具有寻址的属性(lvalue),又具有寻值的属性(rvalue)

#50


那既具有寻址的属性(lvalue),又具有寻值的属性(rvalue)
那const不一样么?

#1


(x.f)();
改为
(x.*f)();

#2


还是不行,它提示:
invalid use of non-static member function `int A::fc()' 
cannot convert `int (A::)()' to `int (A::*)()' in assignment 

我用的是dev c++

#3


#include<iostream>
#include<conio.h>
using namespace std;

class A
{public:int fc(void);
 
 private:int a;};  
   
int main()
{int (A::*f)(void);

 A x;
 x.fc();
 f=&A::fc;
 (x.*f)();
 
 getch();
 return 0;}


int A::fc(void)
{cout<<"a="<<a<<endl;
    a+=5;
 cout<<"a="<<a<<endl;}

#4


f=A::fc;
改成
f=&A::fc;
我用的g++

#5


哦,对,是的,一定要那样的。
刚刚用VC试,改了两种,结果回复楼主的时候,忘了前边的人,就只写了后边一处,呵呵。

#6


f=&A::fc;

DEV 通过并正常运行

#7


靠,怎么打错了那么多字。。。。。

刚刚用VC试,改了两处,结果回复楼主的时候,忘了前边的了,……

#8


0790,分都给我吧:)

#9


那为什么一般的函数又不用取地址&呢?
void fun()
{...}
void (*pf)();
pf = fun;

pf = &fun
都是对的

#10


恩,我也有这个疑问,希望高手解答一下,谢谢~~~

#11


在C++语言中,对于一个由类名加俩冒号再加成员名构成的东西(学名叫“quilified-id”),比如:A::x,只有当x是A类的静态成员的时候,A::x才能表示一个左值。

而对于函数类型到函数指针类型的默认转换,只有当函数类型是左值的时候才行。所有对于非静态的成员函数,就不存在这种从函数类型到函数指针类型的默认转换,于是编译器也就不知道这个
p = A::f
该怎么搞了。

#12


其实静态的成员就是global的,所以与普通的函数有相同的地位。但为什么非静态函数就不行,就算它的调用方式__thiscall与全局函数的__cdecl是不同的,但它的函数地址难道不也是确定的吗,那编译器为什么不知道怎么处理呢?还有,函数类型的左值是什么概念?

#13


学到了,我原先也有这个疑问

#14


To: blue_zyb()
我前面的回复只是基于C++标准中的一些规则的推理而已。换句话说,从C++标准的规定中,可以非常容易地推出对于楼主的问题,那个“&”是绝对不能省略的。但至于C++语言为何这样设计,我目前的理解也很有限。:P

对于这个问题我个人理解只有以下这些,不一定正确:
(1)要说函数地址确定不确定,由于非静态成员函数指针可以有多态行为,因此,至少在编译期,其地址还真的无法确定。
(2)虽然所有的编译器都肯定会把类的非静态成员函数的代码只生成一份(不管是编译时还是运行时),这一点跟非静态成员变量不一样,变量每个对象都有独立的一份。——但我认为,这依然是编译器的实现细节而已,而不是语言特性。从抽象的语言特性角度讲,非静态的成员函数跟非静态的成员变量一样,在没有对象实例的时候,是形不成左值的。

最后,关于全局或静态函数类型为什么是“左值”,我也不是很理解。:P。我目前倒是觉得全局和静态函数名跟数组名差不多,应该只是个右值才对。但C++标准上的确是那样赫然写着的。:(
不过我每次联想到Windows平台上在使用LoadLibrary把一个模块加载到内存后,“竟然”可以GetProcAddress,我就觉得函数和数组还真的不大一样——既然可以找到它,那么除了有一个地方存着它之外,还有别的解释吗?理论上一个黑客完全可以通过修改内存把一个函数的入口地址改掉,让你找不到。其效果就像那种通过技巧修改常量差不多(注意const修饰的常量也是左值)。
可能思路有些混乱了,期待高手出现。

#15


学到了,谢谢steedhorse(晨星) ,希望能有高手继续出现来讨论这个问题~~~~~

#16


对于steedhorse(晨星)上面的论述,我也发表一点自己的看法,也不一定正确 :)
(1)要说函数地址确定不确定,由于非静态成员函数指针可以有多态行为,因此,至少在编译期,其地址还真的无法确定。

    对于函数的多态行为,虽然是在运行时,根据基类所指的具体对象所包含的虚函数表来找到对应的函数地址,但这个地址难道不是在编译时确定的吗,否则编译器是根据什么填好这个虚函数表的呢?并且,多态行为是与对象指针挂钩的,这里用的是类作用域,需要考虑多态吗?何况楼主的例子中也没有用到多态。
////////////////////////////////////

(2)从抽象的语言特性角度讲,非静态的成员函数跟非静态的成员变量一样,在没有对象实例的时候,是形不成左值的。

     但从具体实现来讲,非静态的成员变量是包含在对象内部的,为一个对象分配空间,它的成员才能分配到相应的存储空间。但毕竟函数是独立于对象之外的,它应该占有自己独立的代码空间。所谓左值,就是代表一块编译时分配好的存储空间。所以,成员变量需要依赖对象而存在,成员函数就没有必要了吧。

/////////////////////////////////////////////
最后,关于全局或静态函数类型为什么是“左值”,我也不是很理解。:P。我目前倒是觉得全局和静态函数名跟数组名差不多,应该只是个右值才对。

函数类型是一个左值,我的理解正如前面所说,左值意味着编译时分配好的一块存储空间。那么对于函数来说,函数对应了一段代码,这段代码所占空间的整体构成了这块存储空间,而函数名用来引用这块空间。这就好像int a;为a分配的那4个字节构成了存储空间,而a这个名字用来引用这4个字节的空间。只是a的值被解释为integer,而函数名被解释成什么呢?你不能说函数名的值是哪一大堆二进制的代码值吧,所以函数名被解释成函数代码的起始地址。而类似&fun的写法,则表示取函数所占存储空间的地址,也是函数的首地址。

数组名其实也是一个左值,an arrayname is an l-value but not a modifable l-value(Expert C)。所以也许,函数名也是一个not modifable l-value.

///////////////////////////////////////////////////////////////
(注意const修饰的常量也是左值)
C++中,除了*分配存储空间的情形外(比如对const取地址和extern const),编译器是不必为const分配存储的。也就是说在没有为const分配存储空间的情形下,编译器会在compile time进行常量折叠,这时的const就不构成一个左值。

#17


//所以,成员变量需要依赖对象而存在,成员函数就没有必要了吧。
——你好象还是没有区分开编译器的实现细节和语言的语法特性,从理论上讲,我为每一个对象都生成一份成员函数的代码,虽然效率非常非常非常低,但你不能说我“错”,丝毫没有错,也仍然可以实现C++语言的所有功能。

//编译器会在compile time进行常量折叠,这时的const就不构成一个左值。
——这个也是概念问题,是不是左值,只跟语言语法的定义有关,跟编译器的实现及优化毫无关系。在特殊的情况下,非const量也照样可以被编译器优化掉(比如定义了但没有使用的变量),但它仍然是左值。原因就是“左值/右值”是个语法概念,没有这个概念就难于描述一种编程语言。但它跟实际的编译器实现并没有什么直接关系。概念而已,没啥实际的道理可讲,C++标准就是这样规定的:一切const量都是左值——优不优化是编译器的事,语言不管。

#18


呵呵,我确实没有研究过C++的标准。。。

#19


但是如果写成
f=A::fc;
(x.*f)();
在vc6.0下一样可以通过编译的阿
  那steedhorse(晨星) 所说的  那个“&”是绝对不能省略的  是不是就有点。。。。

#20


还真的来。。。。
不仅VC6,连VC2003也过了。
无语了,微软的东西总是能让人震撼。。。。

#21


To:steedhorse(晨星)
我手头有C++标准,"一切const量都是左值"这一句在什么位置?

#22


精彩!收藏!

#23


看来关于const量是否左值这个问题上,我犯错误了。
以前曾就这个问题跟一个对C语言标准非常熟悉的朋友讨论过,后来就一直想当然的那么理解了。关于const量的左右值这个问题,我就自己没有找到第一手证据就妄作分析可能对别人造成的误导道歉。

不过我现在也不敢说它“有时可能不是左值”,我想进一步确认一下这个问题。虽然这个问题是后面不小心引出来的,但希望楼主先不要结帖,再听听别人对这个问题的意见。:P

至于楼主的问题本身,C++标准的原文如下
ISO/IEC 14882 Second edition 2003-10-15 5.3.1.3

A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed in parentheses. [Note: that is, the expression &(qualified-id), where the qualified-id is enclosed in parentheses, does not form an expression of type “pointer to member.” Neither does qualified-id, because there is no implicit conversion from a qualified-id for a nonstatic member function to the type “pointer to member function” as there is from an lvalue of function type to the type “pointer to function” (4.3). Nor is &unqualified-id a pointer to member, even within the scope of the unqualified-id’s class. ]

#24


const qualified obj是lvalue的证据刚刚在C99的6.3.2.1找到了
A modifiable lvalue is an lvalue that does not have arry type, does not have an incomplete type, does not have a CONST-qualified type, ...

#25


谢谢cber大侠,呵呵。很少看到您老人家关注技术帖子了。:P

const修饰的常量的确是左值,是个"unmodifiable lvalue"。
虽然C++标准(ISO/IEC 14882 Second edition 2003)中的说的不像C语言标准里那么直接明了(这是不是好些对C更熟悉的的朋友更清楚这个问题的原因?),但还是可以找到证据:
(1)首先,3.9.3节详细地介绍了cv-qualifier,讲解了cv-qualified type定义的object和与其对应的cv-unqualified类型对象的联系。尤其这句:The presence of a const specifier in a decl-specifier-seq declares an object of const-qualified object type; such object is called a const object.
(2)然后,紧接着在3.10节的第二款,就给lvalue下了个定义:An lvalue refers to an object or function. Some rvalue expressions—those of class or cv-qualified class type—also refer to objects.
(3)从第三节往后,就是一些具体的说明或特殊情况的说明,包括一些虽然也引用对象,但却不是左值的情况。但所有这些特殊情况的中,没有再提倒cv-qualified type定义的const object,换句话说,const object作为一个object,除了是左值,已经没有需要补充的了。
(4)注意第9款说的“Class rvalues can have cv-qualified types;”仅仅是对第2款后半句的进一步解释,而关于这种“class rvalue”所指代的东西,在针对第二款的脚注47中已经有个说明:Expressions such as invocations of constructors and of functions that return a class type refer to objects, and the implementation can invoke a member function upon such objects, but the expressions are not lvalues.即函数调用和构造函数能产生class类型的对象,而且也可以在这些对象上调用成员函数,但作为一个表达式,它只有右值。
(5)第13,14款再次强调了modifiable的问题,我认为这是针对const type的。除了const type外,我想不出还有几种“nonmodifiable lvalue”了。

所以,const修饰符所定义的对象就是一种“unmodifiable lvalue”。

当然,这样理解太累了,关于const type对象是左值,有两个最好的佐证:
(1)它可以被取地址(注意“左值”并没有复杂成一个“动态”的概念。“可以”就足以说明问题了,因为C++语言从来不允许对右值取址)。
(2)它可以被引用。
所以,只要在程序中看到:const int M = 12345;这种,就可以说M是个左值了,而不必等到把后续的代码全部审视过,把其它的所有源文件也都检查过,确定没有被取址后,才可以放心大胆地说这是个左值。“左值”这个概念是“静态”的,一种表达式的内在属性而已,没有复杂到此种程度。也没有这种说法:你在另外一个文件里加了一行程序,就把另一个文件的一个右值表达式给变成左值表达式了。

最后,再说说刚才的那句“C++语言从来不允许对右值取址”,或许有朋友要挑刺了:“哈哈,楼主的问题不就是个反例吗?那个A::fc就不是左值,怎么也用了‘&’取址了”。前面只是为了先把那个问题说清楚而偷的一点懒而已,事实上确实不能说“C++语言从来不允许对右值取址”,在5.3.1中,C++标准的原话是:“The result of the unary & operator is a pointer to its operand. The operand shall be an lvalue or a qualifiedid.”,也就是说,“&”做取址运算符时只能作用于左值,或者:qualified-id——也就是A::fc这种东西。

#26


我的理解来自于Thinking in CPP(version 2)的chapter8 Constants. 要从头浏览才能更好的理解,但这里摘几段来说明一下我的理解。

首先要说明的是C和C++中的const是不尽相同的,所以不能用C99标准(C标准)来推断C++中的标准。

#1先摘一段对C++中const的说明:
Normally, the C++ compiler avoids creating storage for a const, but
instead holds the definition in its symbol table. When you use
extern with const, however, you force storage to be allocated (this
is also true for certain other cases, such as taking the address of a
const). Storage must be allocated because extern says “use external
linkage,” which means that several translation units must be able to
refer to the item, which requires it to have storage.
In the ordinary case, when extern is not part of the definition, no
storage is allocated. When the const is used, it is simply folded in at
compile time.
The goal of never allocating storage for a const also fails with
complicated structures. Whenever the compiler must allocate
storage, constant folding is prevented (since there’s no way for the
compiler to know for sure what the value of that storage is – if it
could know that, it wouldn’t need to allocate the storage).

#2下面再摘一段关于C++中const与C中不同之处的说明:
Constants were introduced in early versions of C++ while the
Standard C specification was still being finished. Although the C
committee then decided to include const in C, somehow it came to
mean for them “an ordinary variable that cannot be changed.” In C,
a const always occupies storage and its name is global. The C
compiler cannot treat a const as a compile-time constant. In C, if
you say
const int bufsize = 100;
char buf[bufsize];
you will get an error, even though it seems like a rational thing to
do. Because bufsize occupies storage somewhere, the C compiler
cannot know the value at compile time.

#3最后摘一段Expert C中关于lvalue 和rvlaue的说明:
The compiler allocates an address (or l-value) to each variable. This address is
known at compiletime, and is where the variable will be kept at runtime. In contrast, the value stored in a variable at runtime (its r-value) is not known until runtime. If the value stored in a variable is required, the compiler emits code to read the value from the given address and put it in a register.

其中#3中的说明可以很好的帮助理解#2中最后的一句话。 Because bufsize occupies storage somewhere, the C compiler cannot know the value at compile time.也就是说在C中,const量是一个lvalue,它occupies storage,它的值(r-value)只有到runtime才可以通过编译器emit code来得到。
再看#2种最后一句。Whenever the compiler must allocate
storage, constant folding is prevented (since there’s no way for the
compiler to know for sure what the value of that storage is )。也就是说,当编译器必须allocate storage(lvalue的含义)的时候,constant folding将被阻止。因为这个时候对于这个const所占storage的值(它的rvalue)编译器不能确定的知道。

所以,在C++中,对于const的处理并不就是C中那样的直接就是lvalue,否则,对于下面的代码
const int size = 10;
int array[size];
就无法成立,因为array定义中用到了size的值,如果size成为了一个lvalue,分配了storage,那么它的值就必须让编译器生成mov eax,dword ptr [size] 之类的代码,然后运行时才能得到,但是数组的分配都是在编译时进行的。

PS:个人理解,不一定全对



#27


呵呵,这里是挺搞的。但我觉得
首先,编译器实现说明不了太多的问题。只要不违反语言标准,编译器为提高效率做任何动作都最天经地义的,不管巧妙到何种程度。编译器当然应该做“avoids creating storage for a const”这种事,既使是左值也不能放弃一切可能的优化。其实编译器还可以“避免为未使用的变量分配空间”,但这跟理论上的语言特性关系不大。

然后,C++标准中倒是找不到必须为左值分配运行时存储,而且必须在每一处使用其右值的地方都产生运行时读取代码的规定,相反,C++里对左右值的阐述更抽象,丝毫没提内存分配和代码生成。

最后,如果真的如你所说,不是右值就不能定义数组。那万一在那个定义const的源文件中,先用它定义了个数组,接着又取用了它的地址怎么办?难道让原来的数组定义失效,并产生“不能用运行时左值定义数组”的编译错误吗?

C++标准中对于数组的定义,只从上层的高度提到:bounds必须是constant_expression,而constant_expression可以包含const variables,其它就没说啥了。

不过C++标准为了让这一切不出任何漏洞,倒是很巧妙的“推卸”了责任,说是试图修改const对象的动作,如果不是“ill-formed”,那就是“后果undefined”。——我觉得原因显然是在宣告:它就是准备在编译时取用这个左值的右值,谁要是胆敢干扰这一切后果自负。:)

#28


我觉得C++就是在const的问题上有两手准备,由于const可以作为常量来使用,所以编译器要求
const必须初始化。然后,在编译器实现的内部,它可以把这个值保存在符号表里,而不是像一般的变量那样对待。在需要常量的位置(例如数组定义),它就可以用这个自己保存起来的确定的已初始化的值。至于后面特定情形必须为const分配对应的内存空间,编译器不管,反正我认定我最先看到的const被初始化的值。例如,在VS2005下,
const int size = 10;
cout << size << endl;
int *p = const_cast<int*>(&size);
*p = 11;
cout << size << endl;
上述的代码的输出都是10,也就是说该编译器认定的就是编译时看到size被初始化的那个值(当然也可以说只是VS2005这么做,其实是晨星所说的undefined的行为)。

但我不认为用的就是“这个左值的右值”,因为为左值分配的那个地址是映射到内存中去的,而编译器似乎就是在使用它自己保存在符号表中的值。它直接去取自己数据结构表中的值,而不是到运行时再去取内存中的值。

#29


那说明你还是认为“左值”这个概念至少要涉及运行时的取值。
而我认为事情没有那么复杂,左值就是个左值而已,左它的去吧,只要编译时能确定了值了就不要等到运行时,也不一定真的要分配空间。
但不管怎么说,C++标准不敢说const修饰的量是个右值,那样麻烦就大了。

#30


我发现渐渐的咱们的分析不在C++标准上,而在于“左值”这个概念上了。
你认为“它直接去取自己数据结构表中的值,而不是到运行时再去取内存中的值。”——这就说明不是左值。
而我则感到莫名其妙:为什么这样就一定不是左值了?

#31


因为我按照Expert C中所说,The compiler allocates an address (or l-value) to each variable.In contrast, the value stored in a variable at runtime (its r-value) is not known until runtime. 
所以我认为,如果一个变量名构成了一个左值(也就是说为它分配了存储,并对应了一个地址),那么取它的值(也即右值)就要等到运行时才知道。也就是说,对于最简单的一句
int a ;编译器为a分配了一个地址,然后到程序运行时,把为a分配的地址映射到内存中。a的值(rvalue)只有这时才可以知道(即使在上面的情况下a里面的值是垃圾)。而const的值明显在编译时已经确定。

至于你说的"左值就是个左值而已,只要编译时能确定了值了就不要等到运行时",那你的意思是
有类似int a = 2; int b = a + 1;的代码,编译器能够分析到a的值为2,所以就不必为a分配空间,然后保存a的值赋给b对吗。但是,如果a的定义是cin >> a;你就不能了吧。主要原因就是左值(分配存储)是一种统一的处理模式和概念,你总不能让编译器对这个a的定义进行分析,对那个b的运行时输入分配存储,并发射代码。毕竟,程序干些什么事是程序自己的事,编译器只是保证我的一套翻译模式能够确保程序的运行,你总不能让它帮助你去分析或执行程序的运行吧。

#32


“但是,如果a的定义是cin >> a;你就不能了吧。”
——所以说,左值就是左值,虽然某些特殊的况下某些特殊的编译器可以优化它的存储和访问,但作为一个表达式,它是左值已经由语法决定了。
——我倒觉得,正如你所举的例子,从表面上看,“左值”的最大特点之一就是“不可能在所情况下都被优化没了”——总是存在你无法优化的情况。否则干粹规定它是右值不就得了?一了百了。

#33


或者说,我认为,右值不右值对应的主体是你的程序,而不是编译器,虽然编译器代码运行可以知道int a = 2;中的2这个具体的数值,但是不到你的程序运行,a对应的右值2也是不得而知的。所以,我认为右值就对应了"程序运行时"的概念。

#34


这个不太对吧,字面常量和常量表达式也是右值,比如:
2
365 * 24
"0123456789"[7]
等等。

还有,你刚才举的那个例子在多线程下是不可优化的。单线程下也不太会优化这种,我觉得,可能会优化的是这种:
int a = 5;
int b = a;
//....此后a再也没被用过。

#35


错了错了。
"0123456789"[7]
显然是个右值,差点上了自己的当。-_-#

#36


靠,还是打错了,“显然是个左值”。。。。。
BS自己一把。

#37


你也提到优化的问题,你不是总强调语法概念吗 :)

当然,我所讲的是主要是变量对应的rvalue的问题。虽然2, 365 * 24这些是右值,但除非你写2;265*24;之类的代码,一般这些值你还是希望赋给一个变量的吧。那么对于类似int a = 3 + 4;之类的代码,3 + 4是可以通过“运行”编译器的代码分析到,然后它帮你优化成7,但这个a的对应的7个值不是要到你的程序运行时才能在某个内存位置被赋值,然后访问吗,这个a所对应的右值是相对你的程序来说,不是编译器。

至于你上面说的“显然是个右值”是写错了还是怎么回事,"0123456789"[7] = 'z';这句代码在VC6下编译通过,在VS2005下编译失败,错误信息:l-value specifies const object。我曾经用cout << typeid("0123456789").name() << endl;之类的代码试过,在VC下是char [11],而在VS2005中是char const [11]

#38


感觉严重跑题了,后面看的有点吐血

#39


是被你引导的。:(
呵呵,那一段跟主题无关,掐了,别播。。。

哦,那个可能2005更符合标准吧,看来偶可能也被VC耍了一把,还一直以为是对的呢。不讨论了,呵呵。

其实我也想说左右值的判别不该多去讨论编译器,而这点你也提过了:“右值不右值对应的主体是你的程序,而不是编译器”。

我想那我们的分歧就在于对于:
const int M = 5;
我认为现在就可以说“M”这个表达式是左值;
而你认为未必,还得看看,有可能形不成左值,是这样吧?

如果是这样,那我可能就不知道如何往下说了,我认为左右值是个静态的概念,不存在这种情况——就是你已经完全了解了这个表达式每一个组成部分,却仍然要“再往下看看”,才敢说话。因为左右值是表达式本身的固有属性,跟如何被使用无关。

#40


我也觉得说得有点多,不过还是要补充一下:
VS2005下也是把"123456789"[7] 当作左值啊,只是它说这个左值是被const修饰的罢了。我刚突然想到试一下const int a = 10; a = 11;看一下编译器的错误信息会不会是l-value specifies const object。没想到在VC6.0下是,而在VS2005下是:you cannot assign to a variable that is const。呵呵,是不是想太多了。。。

const int M = 5; 我没有说对于要用到M的表达式例如int arr[M]还要往下看看啊,我的意思是编译器现在不一定为M分配了像一般那样变量的对应到内存的空间,但它已经知道我要把它作为一个常量来对待,况且我已经知道它的初始值了,可以用它的初始值来充当常量的角色。至于,后面的代码强迫我为它分配存储,那是后话了,我不管,我先用我自己符号表里的那个值。

#41


“我的意思是编译器现在不一定为M分配了像一般那样变量的对应到内存的空间,但它已经知道我要把它作为一个常量来对待,至于,后面的代码强迫我为它分配存储,那是后话了,我不管,我先用我自己符号表里的那个值。”
——这些俺都没有反对啊,俺只是说它是个“左值”,除此之外,没有别的意思。:(

#42


假设还没有为const分配程序地址空间中对应的地址(Expert C中说The compiler allocates 的address 就是l-value),那现在它算是编译器地址空间中的左值吧,还不算你的程序的。呵呵,晕啊晕~~

#43


怎么又说到编译啊,运行的上去了。。。。

M,一个const int型的object(这是标准中的术语,不是指类实例的那个“object”)。
当它做为一个表达式的时候到底是左值还是右值,真的有必要考虑那么多吗?:(

#44


左值就一定要有空间吗?
正确的说法是:“左值不可能在任何情况下都没有空间”。

#45


除了讨论的const,找一个左值不一定有空间的例子给我一下

#46


Expert C是说C的,而C的const与C++的const的区别你前面自己又不是没说过。
它们的相同点是都是左值。
不同点是,C里它是有空间的,所有Expert C中可以轻轻松松地说“地址就是左值”——至少它们有直接的联系。

但C++中const量不一定有空间,所以C++标准就不敢这么说了。
而且C++想了想临时变量虽然只是右值,也需要编译器分配空间,就不更敢这么说了。

#47


左值不一定有空间的。。。。。
——这还少啊?优化呗。。。
int i;
//从此后再也不用i,结果被优化掉了。

但i还是左值——因为这是个语言概念,就是不可以说i是右值。

#48


还有,C++中所有的全局函数,静态成员函数类型都是也都是左值,这一点跟C标准的描述也不一样。

#49


左值不一定有空间的。。。。。
——这还少啊?优化呗。。。
int i;
//从此后再也不用i,结果被优化掉了。

但i还是左值——因为这是个语言概念,就是不可以说i是右值。

哪哪哪,又把优化说进来了吧,所以从语言概念上来说这个i是构成左值的。而且上次我看见你在哪里说过左值右值都只是一个表达式的属性之类的话,那怎么就不能说i是右值。只是说i代表了一块存储,那既具有寻址的属性(lvalue),又具有寻值的属性(rvalue)

#50


那既具有寻址的属性(lvalue),又具有寻值的属性(rvalue)
那const不一样么?