![]() |
1
4
*这里有一个典型的例子:
这不是没有纯虚拟函数的抽象类,但析构函数需要定义(因为当派生类析构函数时将调用它)。
|
![]() |
2
2
1)不一定。有时您为纯虚拟函数提供主体 2)要调用的函数在运行时确定。 |
![]() |
3
1
在代码中编辑之后:
指针指向类型为的对象
一个常见的实现可能有助于您理解,在声明虚拟函数的每个类中,编译器为指向虚拟表的指针保留空间,并且它还生成虚拟表本身,在其中向每个虚拟方法的定义添加指针。对象的内存布局只有那个额外的指针。
当派生类重写任何基类方法时,编译器将生成一个不同的vtable,其中包含指向该级别的最终重写器的指针。基类和派生类的内存布局在
当编译器看到类似
注意,这个答案中有很多人在挥手。所有这些都是实现定义的(语言没有指定调度机制),在大多数情况下,调度机制更复杂。例如,当发生多个继承时,vtable不会直接指向最终的重写器,而是指向一个适配器代码块,该代码块重置第一个隐式
|
![]() |
4
1
不完全是:它可能有一具尸体。更准确的定义是“每当我们将一个方法定义为纯虚拟的时候,这意味着必须在具体的子类中定义(重写)该方法。”
如果在运行时有一个超类(例如形状)的实例,则不必/不必知道它是哪个子类(例如圆或正方形)。
每个类有一个vtable(对于具有一个或多个虚拟方法的任何类)。vtable包含指向类的虚拟方法地址的指针。 每个对象有一个vptr(对于具有一个或多个虚拟方法的任何对象)。vptr指向对象类的vtable。 vtable的大小随着类中虚拟函数的数目而增加。vptr的大小可能是常量。
如果您想调用基类函数,那么(因为它是虚拟的,而虚拟的默认行为是通过vptr/vtable调用最派生的版本),那么您必须这样明确地说,例如:
|
![]() |
rookie · 检查函数模板的所有参数包参数是否属于int 1 年前 |
![]() |
ivaigult · -W转换和隐式字符串到布尔类型转换 1 年前 |
![]() |
rainer · 后台插入程序的初始化 1 年前 |
![]() |
Community wiki · 以理智、安全和高效的方式复制文件 1 年前 |
|
Shefali Kanaujia · 对C中向量的向量进行排序++ 1 年前 |
|
Ma Joonyoung · 粗粒度和细粒度链表的时间比较 1 年前 |