在c ++中对非虚拟,虚拟,纯虚拟继承和覆盖进行基础处理

时间:2017-06-23 08:13:52

标签: c++ oop inheritance polymorphism function-overriding

我知道每个成员函数中只有一个实例存在于内存中,并且该类的每个对象都使用它,但是你可以通过解释它是如何理解非虚拟和虚拟继承和覆盖的工作原理来帮助我理解它通常在低水平实现,以及如何在记忆中布置?

2 个答案:

答案 0 :(得分:0)

我不知道在那个级别上可以轻松获得大量信息。 C ++标准倾向于避免此类实现细节。我所知道的最好的书是#34;在C ++对象模型中#34;作者:Stan Lippman。它已经很老了,但基本面可能仍然有效。

答案 1 :(得分:0)

如何实现继承,虚拟和覆盖不是标准的一部分,每个编译器都可以自由地以任何方式实现它。

虽然,据我所知,以下是大多数编译器通常使用的通用原则:

  • 非虚拟继承本质上是一个隐藏的组合:为基类和派生对象的附加数据分配空间,并置在内存中。
  • 虚拟方法使用 vtable ,它是在类级别定义的指针数组,并且该类的每个实例都有一个指向的指针。该表包含指向虚方法的指针。
  • 当覆盖派生类中的虚方法时,此类使用已覆盖函数的已修改指针定义其新版本的vtable。它的成员将指向指向这个新表的vtable。
  • 纯虚函数通常由vtable中的指针设置为null_ptr(因此" = 0")

当调用虚函数时,编译器实际上会跟随指向vtable的指针,在vtable中读取被调用函数的函数指针,然后运行该函数。

为了更好地理解这一原则的低级实现,您可以查看this article

多重继承会使事情变得更复杂,因为数据会在内存中移位:

  • 使用非虚拟继承,每个父类在派生类的附加数据之前并置在内存中,就像单继承一样。但这意味着当将派生类型向上转换为其基类型之一时,编译器会移动内存,以便复制或指向派生类型的正确部分。
  • 使用虚拟继承时,内存中的布局几乎相同,但在派生类中创建了一个vtable,其中包含基类的偏移量(请参阅{{3}) })。在向上转换时,编译器将使用此值来查找要复制或指向的内存的正确部分。