×
您的位置: 首页 > 编程笔记

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

C++ C语言 单继承 多继承 虚函数 时间:2019-08-01  查看:384   收藏

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


一、单继承

 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,无论参数列表是否相同。此时基类指针指向基类实例则调用基类函数,指向子类则调用子类函数。

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

 

 

0% (0)
0% (0)