Kir*_*rov 28 c++ pointers member-function-pointers function-pointers
指针只是一个地址吗?或者我错过了什么?
我测试了几种类型的指针:
但是指向成员函数的指针更大 - 我的平台上有16B.
三件事:
void*
必须能够"包含"任何指针类型.换句话说,任何指针必须能够被转换为void*
,对吧?如果是这样,那么为什么sizeof( void* )
是8,而sizeof
指向成员函数的指针是16?BoB*_*ish 28
编辑:所以我注意到这几个月后我仍然得到了投票,尽管我原来的答案很糟糕且误导(我甚至不记得我当时在想什么,而且它没有多大意义!)所以我想我会尝试澄清情况,因为人们仍然必须通过搜索来到这里.
在最正常的情况下,你几乎可以想到
struct A {
int i;
int foo() { return i; }
};
A a;
a.foo();
Run Code Online (Sandbox Code Playgroud)
如
struct A {
int i;
};
int A_foo( A* this ) { return this->i; };
A a;
A_foo(&a);
Run Code Online (Sandbox Code Playgroud)
(开始看起来像C
,对吧?)所以你会认为指针&A::foo
与普通函数指针一样.但是有一些复杂问题:多重继承和虚函数.
所以想象我们有:
struct A {int a;};
struct B {int b;};
struct C : A, B {int c;};
Run Code Online (Sandbox Code Playgroud)
它可能是这样的:
正如您所看到的,如果您想要指向带有a A*
或a 的对象C*
,则指向开头,但如果要指向它,B*
则必须指向中间的某个位置.
因此,如果C
继承了某个成员函数B
并且你想指向它然后调用a上的函数C*
,它需要知道对this
指针进行洗牌.这些信息需要存储在某个地方.所以它与函数指针混在一起.
现在,对于每个具有virtual
函数的类,编译器都会创建一个名为虚拟表的列表.然后它将一个额外的指针添加到该类(vptr).所以对于这个类结构:
struct A
{
int a;
virtual void foo(){};
};
struct B : A
{
int b;
virtual void foo(){};
virtual void bar(){};
};
Run Code Online (Sandbox Code Playgroud)
编译器最终可能会像这样:
因此,指向虚函数的成员函数指针实际上需要是虚拟表的索引.因此,成员函数指针实际上需要1)可能是函数指针,2)可能是this
指针的调整,以及3)可能是vtable索引.为了保持一致,每个成员函数指针都需要能够满足所有这些要求.这是8
指针的4
字节,调整的4
字节,索引的16
字节,总字节数.
我相信这在编译器之间实际上有很大不同,并且有很多可能的优化.可能没有人像我描述的那样实际实现它.
对于很多细节,请参见本(滚动到"成员函数指针的实现").