物体并不是那么神奇.从本质上讲,一个对象只是由其所有成员的线性集合组成,在成员周围有未指定数量的填充.在布局方面,C++类基本上类似于C结构:
struct Foo {
int a;
char b;
std::string s;
static long q;
void bar() { print(s); log(a); }
static void car() { }
}
Run Code Online (Sandbox Code Playgroud)
暂时忽略成员函数和静态,这可能是这样的:
+= class Foo =+
+-------------+ ---\ <--- Foo * p
| int | s
+-------------+ i
| char | z
+-------------+ e
| <padding> | o
+-------------+ f
| std::string | (F
+-------------+ o
| <padding> | o)
+-------------+ ---/
Run Code Online (Sandbox Code Playgroud)
类的每个对象Foo都像这样存储在内存中.我们需要的唯一额外数据是静态成员,成员函数和静态成员函数.
静态成员只是全局变量.所以我们只有一个全局变量:
+== static__Foo__q ==+
+--------------------+
| long int |
+--------------------+
Run Code Online (Sandbox Code Playgroud)
接下来,静态成员函数只是普通的自由函数:
void static__Foo__car() { }
Run Code Online (Sandbox Code Playgroud)
最后,成员函数:这些函数本质上也只是普通函数,但有一个额外的参数允许它们查找实例成员:
void member__Foo__bar(Foo * p) { print(p->s); log(p->a); }
Run Code Online (Sandbox Code Playgroud)
唯一重要的区别是你不能获得一个普通的自由函数指针来指向成员函数,因为实现函数的实际名称没有公开.引用的唯一方法Foo::bar()是通过指向成员的指针函数void (Foo::*ptfm)() = &Foo::bar.成员对象有点简单:你可以获得一个指向它们的普通指针Foo x; int * p = &x.a;,但是你也可以形成一个指向成员的指针:int Foo::*ptm = &Foo::a;.
那么,如果我们有对象Foo x, y, z;,我们可以使用对实例的指针Foo * pi = &x;和成员指针int &Foo::* ptm = &Foo::a或void (Foo::*ptfm)() = &Foo::bar访问给定实例的相关成员:整数pi->*ptm,和函数调用(pi->*ptfm)()分别.(是的,->*是运营商.)
(函数指针的免费版本不能存在,因为多态(虚拟)函数需要比简单的固定函数指针更复杂的调度机制.)