Pointer to Member
数据成员指针存储的是偏移
#include <iostream>
using namespace std;
struct Foo {
int x;
int y;
};
int main() {
Foo x{2};
int Foo::* px = &Foo::x;
int Foo::* py = &Foo::y;
cout << (unsigned long &)px << endl; // 输出0
cout << (unsigned long &)py << endl; // 输出4
cout << sizeof(px) << endl; // gcc输出8
}
数据成员指针的大小和实现相关。
成员函数指针比一般指针占用更多空间
和编译器相关。gcc 里成员函数指针在 64 位机器下是 16 字节。
如果成员函数不是虚函数:函数地址固定;this 指针偏移也可以通过类型在编译时计算出来。先偏移后调用,应该只需要 8 个字节。
如果成员函数是虚函数:
解释:
https://stackoverflow.com/a/12006882/
存储一个偏移难道还不够吗?
MSVC 的更奇怪,多继承指针比单继承指针的体积大:
#include <iostream>
#include <cassert>
using namespace std;
struct A { void x() {} };
struct B { void y() {} };
struct C: A, B { void z() {} };
struct D { int z; };
int main() {
// x86模式编译
// static_assert(sizeof(&A::x) == sizeof(&B::y));
// static_assert(sizeof(&A::x) == 4);
// static_assert(sizeof(&C::z) == 8);
// static_assert(sizeof(&D::z) == 4);
// x64模式编译
static_assert(sizeof(&A::x) == sizeof(&B::y));
static_assert(sizeof(&A::x) == 8);
static_assert(sizeof(&C::z) == 16);
static_assert(sizeof(&D::z) == 4);
}
使用成员指针访问成员
观察:
#include <iostream>
using namespace std;
struct Foo {
int x;
int y;
};
int main() {
Foo x{2, 7};
int Foo::* px = &Foo::x;
int Foo::* py = &Foo::y;
cout << ((&x) ->* px) << endl; // 2
cout << (x .* py) << endl; // 7
}
可以看出 .*
和 ->*
是特殊的访问操作符(这里为了体现其特殊性加了空格,实际上倾向于不加空格书写)。