请忽略#include 部分,假设它们已正确完成。另外,这可能是特定于实现的(但 vtable 的概念也是如此),但我只是很好奇,因为它增强了我可视化多重继承。 (顺便说一下,我使用的是MinGW 4.4.0)
初始代码:
class A {
public:
A() : a(0) {}
int a;
};
//Edit: adding this definition instead
void f(void* ptrA) {
std::cout<<((A*)ptrA)->a;
}
//end of editing of original posted code
#if 0
//this was originally posted. Edited and replaced by the above f() definition
void f(A* ptrA) {
std::cout<<ptrA->a;
}
#endif
编译并生成目标代码。
在我使用的其他一些编译单元中(包含上述代码的头文件后):
class C : public B , public A {
public:
int c;
}objC;
f(&objC); // ################## Label 1
objC 的内存模型:
//<1> stuff from B
//<2> stuff from B
//<3> stuff from A : int a
//<4> stuff from C : int c
&objC
将包含上面假设的内存模型中的起始地址
编译器如何/何时将其转移到 ?是否在检查呼叫时发生Label 1
?
EDIT::
因为标签 1 似乎是一个赠品,只是让它对编译器来说更加晦涩难懂。请参阅上面编辑的代码。现在编译器什么时候做、在哪里做?
是的,你说得很对。
要完全理解这种情况,您必须了解编译器在两点上知道什么:
- 在标签 1 处(正如您已经确定的那样)
-
函数内部 f()
(1) 编译器知道 C 和 A 的确切二进制布局以及如何从 C* 转换为 A* 并将在调用站点执行此操作(标签 1)
(2) 然而,在函数 f() 内部,编译器仅(需要)了解 A*,因此将自身限制为 A 的成员(在本例中为 int a),并且不能混淆特定实例是否是是否属于其他任何事物的一部分。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)