子类中的这种更改是否需要重新编译依赖于超类的代码?

时间:2013-06-20 22:19:28

标签: c++ g++ vtable

我最近一直在学习关于虚拟桌子的更多“深入”的事情,我想到了这个问题。

假设我们有这个样本:

class A {
 virtual void foo();
}

class B : public A {
 void foo();
}

在这种情况下,根据我所知,每个班级都会有一个vtable存在,并且发送将非常简单。

现在假设我们将B类更改为:

class B : public C, public A {
  void foo();
}

如果C类有一些虚拟方法,B的调度机制会更复杂。两个继承路径B-C,B-A等可能有2个vtable。

从我到目前为止所学到的,似乎代码库函数中还有其他地方如下:

void bar(A * a) {
  a->foo();
}

现在需要使用更复杂的调度机制进行编译,因为在编译时我们不知道“a”是否是指向A或B的指针。

现在回答这个问题。假设我们将新的B类添加到我们的代码库中。我似乎不太可能需要在使用指针A的地方重新编译代码。

据我所知,vtables是由编译器创建的。但是,有可能在重定位期间链接器可以解决此修复问题吗?对我来说似乎很难找到任何可以确定的证据,因此现在就去睡觉了。)

2 个答案:

答案 0 :(得分:3)

void bar(A * a)内,指针肯定是A个对象。 A对象可能是B之类的其他对象的子对象,但这是无关紧要的。 A是自包含的,并且有自己的vtable指针,可链接到foo

当发生从B *A *的转换时,例如使用bar调用B *时,可能会向{{1}添加常量偏移量使它指向B *子对象。如果每个对象中的第一个东西都是vtable,那么这也会将指针设置为A vtable。对于单继承,不需要进行调整。

以下是典型实现的内存:

A

(请注意,| ptr to B vt | members of C | members of B | ptr to AB vt | members of A | B vt: | ptrs to methods of C (with B overrides) | ptrs to methods of B | AB vt: | ptrs to methods of A (with B overrides) | 通常仍然是AB vt的一部分;它们在内存中是连续的。B vt可以追溯到ptrs to methods of B。我只是为了格式清晰,我这样写了。)

ptrs to methods of A转换为B *后,您可以从中获取:

A *

到此:

| ptr to B vt | members of C | members of B | ptr to AB vt | members of A |
^ your B * pointer value

使用| ptr to B vt | members of C | members of B | ptr to AB vt | members of A | ^ your A * pointer value static_cast的{​​{1}}会将指针向后移动,向另一个方向移动。

答案 1 :(得分:0)

不,没有必要重新编译仅依赖于A的代码。

这实际上紧接着"独立翻译"的原则,这是典型的现代C ++编译器所遵循的。您可以通过这种方式编写仅依赖于A的所有代码,它永远不会包含任何提及B的定义。这意味着B中的任何更改都不会触发任何A特定代码的重新编译。这反过来意味着C ++编译器遵循"独立翻译"的原则。必须实现简单继承,多继承,虚拟分派,分层转换等,以便B特定代码中的任何更改都不需要重新编译任何A特定代码。

如果情况并非如此,那么典型C ++编译器的架构必须有很大不同。