假设我们有下面的程序:
class A { public: virtual fun(){}; }; class B:public A { public: virtual fun(){}; }; int main() { A a1; B b1; }
我的问题是,当我们运行这个程序时,会创建多少个vtables和多少个vptrs?
vtables
vptrs
4szc88ey1#
它严重依赖于实现,但通常你会得到一个vtable对象每个类有任何虚函数(类没有虚函数或基地不需要他们),和一个vptr每个对象的类与一个vtable(指向类的vtable)。如果您有多个继承和虚基类,事情会变得更加复杂--这可以通过多种方式实现。一些实现对每个额外的基类使用一个附加的vtable(所以最终每个基类每个类都有一个vtable),而其他实现则使用一个包含额外信息的vtable。这可能导致每个对象需要多个vptr。B中的virtual关键字是无关紧要的--如果函数在基类中是虚的,那么它在派生类中也是虚的。
virtual
7kqas0il2#
这个程序可以被优化为完全像这样:
int main(){}
所以,“没有”是一种可能性。
qij5mzcb3#
基本上,2。一个用于class A,一个用于class B(vftables),2个vfptr,一个用于a1,一个用于b1。
class A
class B
a1
b1
**但是,这不是标准的强制要求,所以你也可以没有。(通常实现使用vftables,但它不是强制性的。
注意@R. Martinho Fernandes在优化打开的情况下,您将不会创建任何对象,因此不会创建vfptrs。
vfptrs
gcxthw6b4#
注意,这是严格依赖于实现的。
C++标准没有谈到vptr或vtable,虚拟机制作为编译器的实现细节被排除在外。因此,实际上,编译器可以在不使用vptr或vtable的情况下实现它。然而,几乎所有已知的编译器都使用vptr和vtable来实现它。鉴于上述情况,回答您的问题:每个类都有自己的虚拟表。而每个对象都有自己的虚拟指针。
vptr
vtable
ix0qys7i5#
只有当基类中至少有一个虚函数时,才会创建虚表,这将以任何方式继承到派生类。即使你从派生类B中删除了virtual关键字也没关系,因为你已经在A中获得了一个virtual fun()。因此,虚拟表的数量将是2(作为其每个类的基础),并且虚拟ptr的数量也将是2(作为其每个对象的基础)。VTABLE for A---v_ptr*,A::fun()B的& VTABLE--- V_ptr*(继承自A),B::fun()/* B可以访问A::fun和B的fun(),但由于我们提到A::fun()是虚拟的,B的虚拟表填充了函数fun()的最派生版本,它只不过是B::fun()。希望这能消除你的疑虑
kse8i1jr6#
将有2个vtables,一个用于A类,一个用于B类。将有3个vptrs,一个在a1中,两个在b1中(一个指向class A的vtable,另一个指向class B的vtable)。
6条答案
按热度按时间4szc88ey1#
它严重依赖于实现,但通常你会得到一个vtable对象每个类有任何虚函数(类没有虚函数或基地不需要他们),和一个vptr每个对象的类与一个vtable(指向类的vtable)。
如果您有多个继承和虚基类,事情会变得更加复杂--这可以通过多种方式实现。一些实现对每个额外的基类使用一个附加的vtable(所以最终每个基类每个类都有一个vtable),而其他实现则使用一个包含额外信息的vtable。这可能导致每个对象需要多个vptr。
B中的
virtual
关键字是无关紧要的--如果函数在基类中是虚的,那么它在派生类中也是虚的。7kqas0il2#
这个程序可以被优化为完全像这样:
所以,“没有”是一种可能性。
qij5mzcb3#
基本上,2。一个用于
class A
,一个用于class B
(vftables),2个vfptr,一个用于a1
,一个用于b1
。**但是,这不是标准的强制要求,所以你也可以没有。(通常实现使用vftables,但它不是强制性的。
注意@R. Martinho Fernandes在优化打开的情况下,您将不会创建任何对象,因此不会创建
vfptrs
。gcxthw6b4#
注意,这是严格依赖于实现的。
C++标准没有谈到
vptr
或vtable
,虚拟机制作为编译器的实现细节被排除在外。因此,实际上,编译器可以在不使用vptr
或vtable
的情况下实现它。然而,几乎所有已知的编译器都使用vptr
和vtable
来实现它。鉴于上述情况,回答您的问题:
每个类都有自己的虚拟表。
而每个对象都有自己的虚拟指针。
ix0qys7i5#
只有当基类中至少有一个虚函数时,才会创建虚表,这将以任何方式继承到派生类。即使你从派生类B中删除了virtual关键字也没关系,因为你已经在A中获得了一个virtual fun()。因此,虚拟表的数量将是2(作为其每个类的基础),并且虚拟ptr的数量也将是2(作为其每个对象的基础)。VTABLE for A---v_ptr*,A::fun()
B的& VTABLE--- V_ptr*(继承自A),B::fun()/* B可以访问A::fun和B的fun(),但由于我们提到A::fun()是虚拟的,B的虚拟表填充了函数fun()的最派生版本,它只不过是B::fun()。希望这能消除你的疑虑
kse8i1jr6#
将有2个
vtables
,一个用于A类,一个用于B类。将有3个vptrs
,一个在a1中,两个在b1中(一个指向class A的vtable
,另一个指向class B的vtable
)。