C/C++左值性精髓(三)左值转换----从函数到指针的转换

将函数转换为指针的目的,与数组到指针的转换一样,都是为了将符号数值化,以利于表达式计算。该条款规定:

        A function designator is an expression that has function type. Except when it is the operand of thesizeofoperator or the unary&operator, a function designator with type ‘‘function returningtype’’ is converted to an expression that has type ‘‘pointer to function returningtype’’.

除了几种例外,一个具有函数类型的函数指示符被转换为指向该函数实体的指针。在C中,严格来讲,函数到指针的转换并不属于左值转换,因为C中的函数既不是左值,也不是右值,也正因为这个原因,C中的条款内容并没有指出转换的左值性。但对于C++,函数属于左值,因此该转换属于左值转换,结果是一个右值指针。

        关于C++函数的左值性,有一个例外,就是非静态成员函数不是左值。笔者最初对此感到非常迷惑,因为从抽象本质上说,非静态成员函数并没有不符合C++左值涵义之处。笔者曾经向C++的创始人Bjarne Stroustrup博士发了一封email,向他请教这个问题,BS在回复中说,他认为这个规定是一种不太优雅的技术处理方式,以区别普通函数和非静态成员函数。就是说,这是一个人为规定。由于非静态成员函数被剔除出左值范畴,也导致非静态成员函数不存在从函数到指针的转换,非静态成员函数指针必须通过&运算符获得,例如:

struct A

{

void foo( void );

};

void ( A::*p )( void ) = A::foo;      //A

void ( A::*q )( void ) = &A::foo;     //B

A是错误的,因为非静态成员函数的隐式转换不存在,B才是正确的。

        对于使用函数指针进行函数调用,存在两种方式,分别为:

p();           //A

( *p )();      //B

两种方式都是合法的。因为,函数调用表达式要求其后缀表达式操作数的类型是函数指针,使用普通函数名进行函数调用时,其实是先将函数名转换为函数指针再进行调用的。这是第一种方式成立的原因。而第二种方式,*是解引用运算符,对一个函数指针进行解引用的结果是该指针指向的函数类型,然后该函数类型又通过函数到指针的转换变回函数指针类型,最后再进行函数调用。两种方式其实是殊途同归。第二种方式还可以产生某些有趣的形式,例如:

( ***p )();

( **********p )();

( ************************p )();

这些解引用运算符可以用上述类似的方式无限填充下去,但结果都是一样的,只需要不断进行解引用和函数指针转换就行了。

你可能感兴趣的:(c/c++,左值)