• C++单继承、多继承情况下的虚函数表分析


    C++的三大特性之一的多态是基于虚函数实现的,而大部分编译器是采用虚函数表来实现虚函数,虚函数表(VTAB)存在于可执行文件的只读数据段中,指向VTAB的虚表指针(VPTR)是包含在类的每一个实例当中。当使用引用或指针调用虚函数时,首先通过VPTR找到VTAB,然后通过偏移量找到虚函数地址并调用。

    本文参考:1.http://blog.lucode.net/programming-language/cpp-vtab-and-call-convention.html

      2.https://blog.csdn.net/tangaowen/article/details/5830803

      3.《深度探索C++对象模型》

    一、单继承

     1 #include<iostream>
     2 #include <stdio.h>
     3 using namespace std;
     4 class A {
     5 public:
     6     void func() {
     7         cout << "A::func()" << endl;
     8     }
     9     virtual void func1() {
    10         cout << "A::func1(): " << endl;
    11     }
    12 
    13     virtual void func3() {
    14         cout << "A::func3(): " << endl;
    15     }
    16 };
    17 
    18 class B: public A {
    19 public:
    20     virtual void func() {
    21         cout << "B::func()" << endl;
    22     }
    23     virtual void vfunc() {
    24         cout << "B::vfunc()" << endl;
    25     }
    26     void func1() {
    27         cout << "B::func1(): " << endl;
    28     }
    29 };
    30 int main() {
    31     typedef void (*Fun)(void);
    32     B a;
    33 
    34     Fun *fun = NULL;
    35     fun = (Fun*) ((int *) *(int *) &a);
    36 //    fun = *(Fun **) &a;
    37     fun[0]();
    38     fun[1]();
    39     fun[2]();
    40     fun[3]();
    41 
    42     return 0;
    43 }

    运行结果:

    B::func1():
    A::func3():
    B::func()
    B::vfunc()

    二、多重继承

     1 #include<iostream>
     2 #include <stdio.h>
     3 using namespace std;
     4 class B1 {
     5 public:
     6     virtual void barB1() {cout << "B1::bar" << endl;}
     7     virtual void fooB1() {cout << "B1::foo" << endl;}
     8 };
     9 
    10 class B2 {
    11 public:
    12     virtual void barB2() {cout << "B2::bar" << endl;}
    13     virtual void fooB2() {cout << "B2::foo" << endl;}
    14 };
    15 
    16 class D : public B1, B2 {
    17 public:
    18     void fooB1() {cout << "D::foo" << endl;}
    19     void barB2() {cout << "D::bar" << endl;}
    20 };
    21 
    22 typedef void (*Func)();
    23 int main() {
    24     D tt;
    25     Func* vptr1 = *(Func**)&tt;
    26     Func* vptr2 = *((Func**)&tt + 1);
    27 
    28     vptr1[0]();
    29     vptr1[1]();
    30     vptr1[2]();
    31     cout<<"\\\\\\"<<endl;
    32     vptr2[0]();
    33     vptr2[1]();
    34 
    35     return 0;
    36 }

    运行结果:

    B1::bar
    D::foo
    D::bar
    \\\
    D::bar
    B2::foo

    结论:

         多重继承会有多个虚函数表,几重继承,就会有几个虚函数表。这些表按照派生的顺序依次排列,如果子类改写了父类的虚函数,那么就会用子类自己的虚函数覆盖虚函数表的相应的位置,如果子类有新的虚函数,那么就添加到第一个虚函数表的末尾。

      

    再简单总结一下 覆盖 隐藏 重载 的区别:

    覆盖 是C++虚函数的实现原理,基类的虚函数被子类重写,要求函数参数列表相同;

    隐藏 是C++的名字解析过程,分两种情况,基类函数有virtual,参数列表不同,或基类函数没有virtual,无论参数列表是否相同。此时基类指针指向基类实例则调用基类函数,指向子类则调用子类函数。

    重载 是在同一命名空间中根据参数对同名函数的区别。

    // 我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3ph7kzdx2saoo

    种树最好的时间是十年前,其次是现在。
  • 相关阅读:
    hdu 1087(LIS变形)
    poj 1088(记忆化搜索)
    hdu 1505(最大子矩阵)
    hdu 1506(好题+DP或者RMQ)
    poj 2593&&poj2479(最大两子段和)
    hdu 1003(最大子段和)
    hdu 2881(LIS变形)
    poj 1692(动态规划)
    CodeForces 626C Block Towers
    CodeForces 626B Cards
  • 原文地址:https://www.cnblogs.com/bobojiang/p/11282446.html
Copyright © 2020-2023  润新知