所以这一次我认为当你做像ObjectA.field1这样的事情时,ObjectA就像堆栈上的任何值一样,你基本上可以访问它的字段。现在我正在阅读有关OOP语言的类的注释,并意识到当你执行ObjectA.field1时实际发生的是HEAP(ObjectA的地址)(field1),它返回field1的值。这让我有点困惑。虽然我们已经拥有对象的价值,但有人能说出为什么会有一个查找吗?希望我能够解释..
答案 0 :(得分:7)
对象并不是那么神奇。从本质上讲,一个对象只是由其所有成员的线性集合组成,在成员周围有未指定数量的填充。在布局方面,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)()
。 (是的,->*
是一个运营商。)
(函数指针的免费版本不能存在,因为多态(虚拟)函数需要比简单的固定函数指针更复杂的调度机制。)
答案 1 :(得分:3)
要获取某些field1
某些ObjectA
的{{1}},计算机必须拥有包含ClassA
的内存区域的地址,它才能(静态地)知道偏移量ObjectA
(field1
)的(以字节为单位),以便通过将该偏移量添加到ClassA
的地址来检索field1
。