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

Dic4000 2006-09-06 11:39:06
下面这个程序使用函数指针指向类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;}


...全文
1628 73 打赏 收藏 转发到动态 举报
写回复
用AI写文章
73 条回复
切换为时间正序
请发表友善的回复…
发表回复
晨星 2006-09-13
  • 打赏
  • 举报
回复
偶还是认为“左值”跟“一块被分配了存储的空间的属性”八竿子打不着。
blue_zyb 2006-09-11
  • 打赏
  • 举报
回复
再来谈一下我对左值的理解。
我认为左值右值实际上只是一块被分配了存储的空间的属性,也就是说,左值是这块空间的地址,而右值是这个存储空间中存储的值。只不过由于编译器分配一个存储空间以后,就用一个特定的地址值与之相关联(这个地址值就是l-value),所以我们可以用这个地址值来引用这块存储空间。所以,我认为,成为左值的必要条件是为之分配了相应的存储空间。从源代码上层面看,字符符号又会与那个分配了存储的地址值相关联,所以我们可以用一个符号来引用分配的存储空间。我们习惯上就把这个符号称作左值,因为它确实就是与实际的左值(一个地址值)对应起来的。

并且,我认为,作为C++中的左值,分配了存储是必要条件,但似乎还不是充分条件。例如,临时存储空间并不构成左值的概念,为什么呢?我认为成为左值的另一个条件是“左值是符号可引用的”。什么意思呢?例如,我们都知道,对于int a = 10;那么a肯定是一个左值,因为编译器不仅为它分配了空间,还把a这个字面上的符号与所分配空间的地址关联起来了,所以我们以后就可以用a这个符号(实际上是这个符号对应的地址)来引用实际分配的存储空间。但对于表达式计算中或函数返回的临时对象,为什么概念上不构成左值呢?因为虽然为它们开辟了存储,但是它们不是我们直观上能“符号引用的”,也就是说,编译按自己特定的实现把它们放在一块存储区域,但我们却不能用一个特定的字面符号来引用他们。这不像int a;一样,我们明确告诉编译器我就是要用a这个符号引用你为我分配的存储空间。

所以,对于const量来说,我并不是说“本来它是右值,取地址就使它成为了左值”,而是说取地址会强迫编译器为之分配存储(因为这个取地址必定是取程序地址空间中的存储空间的地址,而不是编译器符号表中表示const量的那个地址,所以编译器必定要为之分配一个对应程序地址空间中的存储),从而构成了概念上成为左值的必要条件。否则,对于一般的情形,编译器如果只是在自己的符号表中记录了const量的值,而不是实际在你的程序的地址空间中为它分配了一个地址,概念上就不构成左值。
zjbirdman 2006-09-09
  • 打赏
  • 举报
回复
guanzhu
晨星 2006-09-08
  • 打赏
  • 举报
回复
呵呵,这里是挺搞的。但我觉得
首先,编译器实现说明不了太多的问题。只要不违反语言标准,编译器为提高效率做任何动作都最天经地义的,不管巧妙到何种程度。编译器当然应该做“avoids creating storage for a const”这种事,既使是左值也不能放弃一切可能的优化。其实编译器还可以“避免为未使用的变量分配空间”,但这跟理论上的语言特性关系不大。

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

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

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

不过C++标准为了让这一切不出任何漏洞,倒是很巧妙的“推卸”了责任,说是试图修改const对象的动作,如果不是“ill-formed”,那就是“后果undefined”。——我觉得原因显然是在宣告:它就是准备在编译时取用这个左值的右值,谁要是胆敢干扰这一切后果自负。:)
blue_zyb 2006-09-08
  • 打赏
  • 举报
回复
我的理解来自于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:个人理解,不一定全对



Arthur_ 2006-09-08
  • 打赏
  • 举报
回复
看得眼睛痛了

感觉语言陷阱与缺陷这本书写得太薄了,应该扩充了。
晨星 2006-09-08
  • 打赏
  • 举报
回复
谢谢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这种东西。
Arthur_ 2006-09-08
  • 打赏
  • 举报
回复
mk
晨星 2006-09-08
  • 打赏
  • 举报
回复
刚才是有点急了,报歉。

还是把自己的最后一点想法再帖一下吧。
C++语言规定,除了类成员之外,只有左值可以取址。
如果规定const量“可以不是”左值,那么取址的行为就没法定义,会产生出鸡生蛋和蛋生鸡的问题——你说不请倒底是取址使它成为了左值,还是因为它是左值所以可以取址。
这样一来,就等于说C++语言在逻辑上又产生个大漏洞。
ets2008 2006-09-08
  • 打赏
  • 举报
回复
精彩!,各位周末去哪玩啊?
晨星 2006-09-08
  • 打赏
  • 举报
回复
是啊,你就是说一个const量本来只是右值,只因为取了一次地址,就“升”为了左值。
这还不疯,那以后还有机会疯吗?:(
blue_zyb 2006-09-08
  • 打赏
  • 举报
回复
你激动了。。。。
我不说了行啵。。。。
晨星 2006-09-08
  • 打赏
  • 举报
回复
你觉得不必要的就一定是不必要的,哪怕有编译器认为必要;
你觉得必要的就一定是必要的,哪怕有编译器认为不必要。

都是你一个人说得算,人家做编译器的万一不按照你说的来就不是“循规蹈矩”,只有完全按照你说的来才算“循规蹈矩”。。。。。
blue_zyb 2006-09-08
  • 打赏
  • 举报
回复
我是说对const的量取地址强迫分配了存储,又不是1,2,3
干嘛疯,我还没疯。。。
晨星 2006-09-08
  • 打赏
  • 举报
回复
于是,“右值可以取地址从而升为左值”????
疯了。。。。。
blue_zyb 2006-09-08
  • 打赏
  • 举报
回复
对阿,就是2,3.3之类的文字常量啊,至于你要说const量可以取地址,是左值,那是因为取地址强迫分配了存储,构成了成为左值的必要条件。const本来就是用来取代define之类的东西的,如果只是要简单的引用几个常量,我干嘛要分配存储。不过const的用法又有多个变种,所以编译器可能为了实现起来方便就统一分配了地址也说不定。不过从概念上说,这不是必要的
晨星 2006-09-08
  • 打赏
  • 举报
回复
天哪。。。
人类历史上最悲惨的事情莫过于半路又杀出个程咬金。。。。。

放弃了。。。。
不知楼上的楼上知不知道啥叫“unmodifiable lvalue”。。。
晨星 2006-09-08
  • 打赏
  • 举报
回复
。。。。。。。
gaoxiaotiger 2006-09-08
  • 打赏
  • 举报
回复
左值就是能做赋运值算符左边的值,例如const 类型就不能做左值了。
晨星 2006-09-08
  • 打赏
  • 举报
回复
什么样的只是右值?一取地址连编译都过不去的那种就只是右值。——除了成员指针。
加载更多回复(53)

64,647

社区成员

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

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