我正在阅读 Bjarne 的论文:“ Multiple Inheritance for C++ ”。
在第 3 节第 370 页中,Bjarne 说“编译器将成员函数的调用转换为带有“额外”参数的“普通”函数调用;“额外”参数是指向成员函数所针对的对象的指针叫做。”
考虑一个简单的类A
:
class A {
int a;
void f(int i);
};
成员函数 A::f 的调用:
A* pa;
pa->f(2)
由编译器转换为“普通函数调用”:
f__F1A(pa, 2)
pa 作为 this 指针传递。上面的例子很容易理解。
考虑以下代码片段:
class A {int a; void f(int);};
class B : A {int b; void g(int);};
class C : B {int c; void h(int);};
问题一:
成员函数 A::f 的调用:
C* pc = new C;
pc->g(int)
由编译器转换为“普通函数调用”:
g__G1C(pc, int) or g__G1B((*B)pc, int)
this 指针是 *pc 还是 (*B)pc?另一个问题是编译器如何知道成员函数在哪里?
让我们通过添加 virtual 关键字使上面的示例更有趣。
class A {
int a;
virtual void f(int);
virtual void g(int);
virtual void h(int);
};
class B : A {int b; void g(int); };
class C : B {int c; void h(int); };
一个 c 类对象 C 看起来像:
C:
----------- vtbl:
+0: vptr --------------> -----------
+4: a +0: A::f
+8: b +4: B::g
+12: c +8: C::h
----------- -----------
对虚函数的调用被编译器转换为间接调用。例如,
C* pc;
pc->g(2)
变成这样:
(*((*pc)[1]))(pc, 2)
Bjarne 的论文告诉了我上述结论。
问题2:
(1) 在 vtbl 中,我相信这些函数指针是在运行时分配的。编译器如何知道第二个函数指针应该指向 B 类对 g 的实现?编译器如何计算它?
(2) 在上面的例子中,所有成员都是 int,我们假设编译器为 int 分配了 4 个字节的内存。如果成员是 char,编译器是否仍为 char 分配 4 字节内存?还是只有一个字节?
(3) (*((*pc)[1]))(pc, 2)
、这里的this指针是pc,为什么不是(*B)pc呢?传递这个指针有什么规则吗?
谁能帮我回答这些问题?对此,我真的非常感激。我明天有一个截止日期,这真的与这些问题有关。请帮忙!!!