【问题标题】:compiler's detail of this pointer and virtual functions编译器的 this 指针和虚函数的详细信息
【发布时间】:2015-06-10 03:12:05
【问题描述】:

我正在阅读 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 指针传递。上面的例子很容易理解。

考虑以下代码sn-p:

class A {int a; void f(int);};
class B : A {int b; void g(int);};
class C : B {int c; void h(int);};

问题 1:

成员函数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) 个人电脑? this指针的传递有什么规则吗?

谁能帮我回答这些问题?对此,我真的非常感激。我有一个 明天的deadline这确实与这些问题有关。请帮忙!!!

【问题讨论】:

  • 这似乎是要看看 Clang/GCC 以获得答案。
  • 不要对未引用的文本使用引号格式,

标签: c++ pointers virtual-functions vtable this-pointer


【解决方案1】:

问题一:

成员函数A::f:的调用

C* pc = new C;
pc->g(int)

这不是对 A::f() 的调用。这是对 B::g() 的调用。

被编译器转化为“普通函数调用”:

g__G1C(pc, int) or g__G1B((*B)pc, int)

this 指针是 *pc 还是 (*B)pc?

两者都没有。这是一个B*

另一个问题是编译器如何知道成员函数在哪里?

它没有。它知道他们的名字。链接器分配它们的地址。

问题 2:

(1) 编译器如何知道第二个函数指针应该指向类 B 的 g 实现?编译器是怎么计算出来的?

因为是C的vtbl,而C继承自B,而B的定义最接近g()。

(2) 在上面的例子中,所有成员都是 int,我们假设编译器为 int 分配了 4 个字节的内存。如果成员是 char,编译器是否仍然为 char 分配 4 字节内存?还是只有一个字节?

这取决于处理器的对齐和打包规则、编译器、编译器选项、周围的#pragmas 等。

(3) (*((*pc)[1]))(pc, 2),这里的this指针是pc,为什么不是(*B)pc?

这个假设与your other question 相矛盾。是B*

this指针的传递有什么规则吗?

见上文。

【讨论】:

  • 非常感谢您的回答。我还有一个问题:stackoverflow.com/questions/30747633/…你能帮我看看吗?
  • 对于问题2,函数指针在运行时或编译步骤指向适当的函数?
  • @Fihop 这不是一个有意义的问题。
猜你喜欢
  • 1970-01-01
  • 2021-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-21
  • 1970-01-01
相关资源
最近更新 更多