一种“标准”的虚函数机制简介

    编译器是如何针对 虚函数产生可以再运行时刻确定被调用函数的代码呢?也就是说,虚函数实际上是如何被编译器处理的呢?Lippman在深度探索C++对象模型中的不同章节讲到了几种方式,这里把“标准的”方式简单介绍一下。

    我所说的“标准”方式,也就是所谓的“VTABLE”机制。编译器发现一个类中有被声明为virtual的函数,就会为其搞一个虚函数表,也就是VTABLE。 VTABLE实际上是一个函数指针的数组,每个虚函数占用这个数组的一个slot。 一个类只有一个VTABLE,不管它有多少个实例。派生类有自己的VTABLE,但是 派生类的VTABLE与基类的VTABLE有相同的函数排列顺序,同名的虚函数被放在两个数组的相同位置上。在创建类实例的时候,编译器还会在每个实例的内存布局中增加一个vptr字段,该字段指向本类的VTABLE。通过这些手段,编译器在看到一个虚函数调用的时候,就会将这个调用改写,针对1.1中的例子:

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

会被改写为:

void bar(A * a)
{
    (a->vptr[1])();
}

    因为派生类和基类的foo()函数具有相同的VTABLE索引,而他们的vptr又指向不同的VTABLE,因此通过这样的方法可以在运行时刻决定调用哪个foo()函数。

    虽然实际情况远非这么简单,但是基本原理大致如此。

你可能感兴趣的:(C++,c,C#)