2009-01-04 39 views
4

我习惯认为成员函数只是普通函数的一个特例,其中成员函数在'this'指针的参数列表的开始处有一个额外的参数,也就是说,成员函数应该起作用。我用的boost ::功能在过去这样的,从来没有遇到过任何问题:C++,指针函数和指向成员函数的等价关系?

boost::function f<(void)(MyObject*, int, int)> = &MyObject::method_that_takes_two_ints; 

但我已经看到了这个语法成员函数指针:

void (MyObject::*f)(int, int) = &MyObject::method_that_takes_two_ints; 

在此语法, 'this'参数不可见。这让我想知道是否在引擎盖下的指针 - 成员函数真的是一个单独的野兽,而这种提升正在照顾我的细节。

该标准规定了'this'参数的位置是什么?也许就在我的编译器中,额外的'this'参数是第一位的,也可能在其他编译器上它可能到最后?我很幸运,我的思维方式与我的编译器(GCC4,VS2005)如何处理它一致?成员函数指针是否只是指向函数的特例,带有额外的参数或者编译器是否可以以不同的方式实现?

回答

10

该标准几乎没有关于this指针应放置在哪里,事实上,对成员函数使用不同的调用约定相当普遍。 (所以this指针不只是一个额外的第一个参数,它实际上是存储在不同的位置比第一个参数通常是)

特别是,MSVC使用成员函数的thiscall调用约定,并stdcall别处。 http://www.hackcraft.net/cpp/MSCallingConventions/#thiscall介绍它们之间的差异,但要注意,thiscall存储在ECX寄存器中的this指针,而stdcall堆栈上的所有参数。

你绝对会把它们当作完全不同的类型对待。指向成员函数的指针是而不是只是指向具有额外参数的函数的指针。

3

是的,指向函数的指针和指向成员的指针是完全不同的野兽。指向成员的指针需要给予一个对象实例,使用->*.*运算符来取消引用。在制作指向成员的指针时使用的参数没有this,因为使用指向成员的指针(->*.*左侧的对象)时会确定this

请注意,指针到成员函数和指向成员变量之间的差别可能比指向成员函数和常规函数指针之间的差异更小。

通常,成员函数和常规函数可以有完全不同的调用约定,因此您不能在它们之间进行投射。

1

它们绝对是不同的类型,所做的任何假设都是平台/编译器特定的。

This page有更多关于成员功能点实现的信息比我想知道的要多,包括许多流行编译器的实现细节。

9

this指针不是沿着指向成员的指针存储的(成员函数指针是这种情况的特例)。如果你只是做

void (MyObject::*f)(int, int) = &MyObject::method_that_takes_two_ints; 

然后存储的只是成员函数应该在objet上调用,你稍后必须提供的信息。如果你想调用它,你必须传递一个对象,其中编译器会从中获取指针this

MyObject o; (o.*f)(1, 2); 

一个成员函数指针仅仅是一个成员指针,其类型(这是指出)是一个函数类型。该标准说,成员函数指针没有它们自己指向的“成员函数类型”,并且会以某种方式包含此指针类型。

int main() { 
    typedef void fun() const; 
    fun MyObject::*mem_function_ptr = 
     &MyObject::const_method_that_takes_two_ints; 
} 

fun该代码是函数类型。 “正常”函数具有的类型。指针到功能,而不是一个成员函数指针,只是一个指向函数具有类型:

void foo() { cout << "hello"; } 
int main() { 
    typedef void fun(); 
    fun * f = &foo; 
} 

虽然指针到成员函数具有额外的构件指针该功能类型的顶层。

一些关于this指针和它如何与它指向(未技术,只是理论的东西)目的:

每个成员函数有一个隐藏参数调用其具有implicit object parameter键入MyObject&MyObject const&取决于你是否有const或nonconst成员函数。您调用成员函数o的对象是implied object argument,它被传递给参数。在构成描述如何调用成员函数的规则的标准理论中,隐式对象参数是第一个隐藏参数。这是概念性的,并不意味着它是实现中的真实案例。然后将隐含的对象参数绑定到该隐式对象参数上,可能导致隐式转换(因此,如果您在非const对象上调用const成员函数,则限定转换将从MyObject转换为MyObject const&。这就是非const函数一个比const函数更好的选择来调用非const对象)。例如,一个可在该代码说:

struct A { 
    operator int() const { return 0; } 
}; 

int main() { 
    A a; 
    int i = a; // implicit conversion using the conversion function 
} 

即暗示对象参数A类型的a势必A const&类型的隐式对象参数,其目的随后由this指针指向具有类型A const*这里。需要注意的是,隐式对象参数只是一个理论构造,用于形式化调用成员函数的规则(而构造函数不包含它们),而这个指针实际上是存在的。 this是一个指针,因为当引入this时,C++还没有引用。

我希望能帮助你理解这件事。

+0

令人印象深刻的答案。 – mahesh 2009-03-06 07:09:11

0

为了补充其他人的回答,Boost.Function通过在成员函数指针上专门赋值操作符来工作,以便它能够检测到你何时通过了它。当你调用该函数时,它将在内部重新解释它,以调用成员函数指针的正确方法((obj->*fun)(args))。

3

请注意,使用不同的编译器时,指向成员函数的指针的大小可能会有所不同。

另一件事要注意,写在The Old New Thing blog

一个 指针到成员函数的大小可以根据类改变 。

1

回答所有问题: 是的,它们是特殊的指针,与普通的指针不同。 是的,boost :: function可以识别它们。

该标准没有提到调用堆栈的内部细节。事实上,许多编译器可能使用整数rergisters,浮点寄存器和/或堆栈,具体取决于实际的参数列表。 'this'指针只是一个特例。

Boost :: function通过内部使用两个代码路径来解决此问题。您可以通过检查这两种情况的调用堆栈来看到这一点。如果boost :: function存储一个指向成员函数的指针,则operator()将分割参数列表。第一个参数用作使用其余参数调用成员函数的对象。