所以一直以来我都认为,当您执行类似 ObjectA.field1 的操作时,ObjectA 就像堆栈上的任何值一样,您基本上可以访问它的字段。现在,我正在浏览有关 OOP 语言的类(class)笔记,并意识到当您执行 ObjectA.field1 时,实际发生的是 HEAP(Address of ObjectA)(field1),它返回 field1 的值。这让我有点困惑。谁能说出为什么我们已经有了对象的值还要进行查找?希望我能够解释..
最佳答案
对象并没有那么神奇。本质上,一个对象仅由其所有成员的线性集合组成,成员周围有未指定数量的填充。在布局方面,C++ 类本质上类似于 C 结构:
struct Foo {
int a;
char b;
std::string s;
static long q;
void bar() { print(s); log(a); }
static void car() { }
}
暂时忽略成员函数和静态,这可能是这样布局的:
+= class Foo =+
+-------------+ ---\ <--- Foo * p
| int | s
+-------------+ i
| char | z
+-------------+ e
| <padding> | o
+-------------+ f
| std::string | (F
+-------------+ o
| <padding> | o)
+-------------+ ---/
Foo
类的每个对象都像这样存储在内存中。我们唯一需要的额外数据是静态成员、成员函数和静态成员函数。
静态成员 只是全局变量。所以我们只有一个全局变量:
+== static__Foo__q ==+
+--------------------+
| long int |
+--------------------+
接下来,静态成员函数只是普通的自由函数:
void static__Foo__car() { }
最后,成员函数:这些本质上也只是普通函数,尽管有一个额外的参数可以让它们找到实例成员:
void member__Foo__bar(Foo * p) { print(p->s); log(p->a); }
唯一重要的区别是您无法获得指向成员函数的普通自由函数指针,因为未公开实现函数的实际名称。引用 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)()
,分别。 (是的,->*
是一个运算符。)
(函数指针的免费版本不存在,因为多态(虚拟)函数需要比简单的固定函数指针更复杂的调度机制。)
关于c++ - 对象的内部表示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8196833/