C++迟后联编和虚函数表

先看一个题目:数组

class Base
{
public:
    virtual void Show(int x)
    {
        cout << "In Base class, int x = " << x << endl;
    }
};

class Derived : public Base
{
public:
    virtual void Show(float x)
    {
        cout << "In Derived, float x = " << x << endl;
    }
};

void test (Base &b)
{
    int i = 1;
    b.Show(i);
    
    float f = 2.0;
    b.Show(f);
}

int main(int argc, char *argv[])
{
    Base bc;

    Derived sc;
    test(bc);
    test(sc);
 
    return 0;
}

输出结果为:D

A、In Base class, int x = 1;
   In Base class, int x = 2;
   In Derived, int x = 1;
   In Derived, float x = 2;
B、In Base class, int x = 1;
   In Base class, int x = 2;
   In Derived, float x = 1;
   In Derived, float x = 2;
C、In Base class, int x = 1;
   In Base class, int x = 2;
   In Base, int x = 1;
   In Base, float x = 2;
D、In Base class, int x = 1;
   In Base class, int x = 2;
   In Base class, int x = 1;
   In Base class, int x = 2;

理由:若是虚函数在基类与子类中出现的仅仅是名字的相同,而参数类型不一样,或者返回类型不一样,即便写上了virtual关键字,也不进行迟后联编。ide

stackoverflow上,能够看到解释,http://stackoverflow.com/questions/27227189/override-virtual-function-with-different-parameters-in-c函数

C++里有两种编译类型:
1) 先期联编或静态联编:在编译时就能进行函数联编称为先期联编或静态联编。
2) 迟后联编或动态联编:在运行时才能进行的联编称为迟后联编或动态联编。spa

virtual关键字的做用就是提示编译器进行迟后联编,告诉连接过程:“我是个虚的,先不要链接我,等运行时再说”。 具体原理:当编译器遇到virtual后,会为所在的类构造一个表和一个指针,那个表叫作vtbl,每一个类都有本身的vtbl,vtbl的做用就是保存本身类中虚函数的地址,咱们能够把vtbl形象地当作一个数组,这个数组的每一个元素存放的就是虚函数的地址,指针叫作vptr,指向那个表。而这个指针保存在相应的对象当中,也就是说只有建立了对象之后才能找到相应虚函数的地址。 .net

对于下面这种常见代码(假如Base是Derive的父类):指针

Base *p=new Derive();
p->virtual_fun();

在程序运行时,根据对象的类型去初始化vptr,从而让vptr正确的指向所属类的虚表。上述程序中,因为p实际指向的对象类型是Derive,所以vptr指向的Derive类的vtable,当调用p->virtual_fun()时,根据虚表中的函数地址找到的就是Derive类的virtual_func()函数。code

 

假设咱们有这样的一个类:对象

class Base {

     public:

            virtual void f() { cout << "Base::f" << endl; }

            virtual void g() { cout << "Base::g" << endl; }

            virtual void h() { cout << "Base::h" << endl; }

};

对应的虚函数表:blog

假设有以下所示的一个继承关系:继承

对于实例:Derive d; 的虚函数表以下:

若是是多继承:

对于实例:Derive d; 的虚函数表以下:

而C++标准规定:为确保运行时的多态定义的基类与派生类的虚函数不只函数名要相同,其返回值及参数都必须相同,不然即便加上了virtual,系统也不进行迟后联编。

所以,对于最初的题目,Base的虚函数表里仅仅有一个Show方法,因为Derived子类重载了Show函数,那么Derived的虚函数表里实际上有两个Show方法,

所以,从Base角度去调用Show方法也只能是调用Base本身的方法了。

 

虚函数表的例子参考了:http://blog.csdn.net/haoel/article/details/1948051

相关文章
相关标签/搜索