文章目录

  • 一.虚函数表定义及特点
  • 二、验证过程
    • 1.测试虚函数表地址和虚函数地址
    • 2.多个类对象的虚函数表地址
    • 3.测试类中无虚函数,是否存在虚函数表
    • 4.子类继承父类,但不继承虚函数表
    • 5.子类重写父类中虚函数,或子类重定义父类虚函数
    • 6.子类指针指向父类
    • 7.子类重写父类虚函数,并子类指针指向父类
  • 结论

一.虚函数表定义及特点

|版本声明:山河君,未经博主允许,禁止转载

虚函数大家都知道是基本用于实现多态的,当父类指针指向子类对象的时候,如何确定调用的函数是父类里的还是子类里面的,这就要用到虚函数表。

1.编译器会为每个有虚函数的类创建一个虚函数表

如有类中没有虚函数,那么这个虚函数表就不存在,而不是表中无数据。同时,所有类都会有自己的虚函数表,一个类不会有另外一个类的虚函数表,包括两个类属于继承关系。

2.虚函数表会被一个类的所有对象所拥有

类的每个虚函数成员占据虚函数表的一行,所以说,如果类中有N个虚函数,那么该虚函数表将会有N*4的大小。并不是每个类对象都会有自己的表。

3.编译器会将虚函数表指针存放在类对象最前面的位置

对于类的每个对象,编译器都会为其生成一个透明不可见的指针,这个指针就是虚函数表指针,存放在该对象内存的最前位置。例如:一个类拥有虚函数表,类对象内存布局中前4个字节就是虚函数表的地址(32位)。这个接下来我们会进行测试。

4.延伸,由第一条可知,子类继承父类,其虚函数表和表函数地址是不一样的。

5.父类指针指向子类时,调用时实际上是根据子类的虚函数表进行查找

二、验证过程

测试内容:
虚函数表地址和虚函数地址存放位置?
多个类对象的虚函数表地址是否一样?
测试类中无虚函数,是否存在虚函数表?
子类继承父类虚函数表地址分别是什么位置?
子类重写父类中虚函数或子类重定义父类虚函数虚函数表是否发生改变?
子类指针指向父类虚函数表是什么样子?

1.测试虚函数表地址和虚函数地址

#include <stdio.h>
#include <stdlib.h>
#include <iostream>using namespace std;class Father
{virtual void FatherFun1() {cout << "FatherFun1" <<endl;}virtual void FatherFun2() {cout << "FatherFun2" <<endl;}virtual void FatherFun3() {cout << "FatherFun3" <<endl;}
};typedef void (*Fun)(void);int main()
{Father father;cout << "类对象地址:" << &father << endl;cout << "虚函数表地址: " << (int*)*(int*)&father << endl;cout << "虚函数FatherFun1地址:" <<(int*)*(int*)&father << endl;cout << "虚函数FatherFun2地址:" <<(int*)*(int*)&father + 1 << endl;cout << "虚函数FatherFun3地址:" <<(int*)*(int*)&father + 2 << endl;cout << "测试地址是否正确" << endl;Fun fun = (Fun)*(int*)*(int*)&father;fun();fun = (Fun)*((int*)*(int*)(&father) + 1);fun();fun = (Fun)*((int*)*(int*)(&father) + 2);fun();system("pause");
}

上面说过类对象内存中前4个字节就是虚函数表的地址,那么我们获取类对象前4个字节,(int)&father就是虚函数表地址,我们再给他转换成地址指针为(int*)(int)&father。

然后我们在看一下输出结果:

类对象地址:003BF90C
虚函数表地址: 00867898
虚函数FatherFun1地址:00867898
虚函数FatherFun2地址:0086789C
虚函数FatherFun3地址:008678A0
测试地址是否正确
FatherFun1
FatherFun2
FatherFun3
请按任意键继续. . .

从这个输出我们可以看到,FatherFun1、FatherFun2、FatherFun3的地址只差了4个字节,且输出是正确的,那么第三点已确认

2.多个类对象的虚函数表地址

#include <stdio.h>
#include <stdlib.h>
#include <iostream>using namespace std;class Father
{virtual void FatherFun1() {cout << "FatherFun1" <<endl;}virtual void FatherFun2() {cout << "FatherFun2" <<endl;}virtual void FatherFun3() {cout << "FatherFun3" <<endl;}
};typedef void (*Fun)(void);int main()
{Father father;cout << "类对象地址:" << &father << endl;cout << "虚函数表地址: " << (int*)*(int*)&father << endl;cout << "虚函数FatherFun1地址:" <<(int*)*(int*)&father << endl;cout << "虚函数FatherFun2地址:" <<(int*)*(int*)&father + 1 << endl;cout << "虚函数FatherFun3地址:" <<(int*)*(int*)&father + 2 << endl;cout << "第二个类对象" << endl;Father father1;cout << "类对象地址:" << &father1 << endl;cout << "虚函数表地址: " << (int*)*(int*)&father1 << endl;cout << "虚函数FatherFun1地址:" <<(int*)*(int*)&father1 << endl;cout << "虚函数FatherFun2地址:" <<(int*)*(int*)&father1 + 1 << endl;cout << "虚函数FatherFun3地址:" <<(int*)*(int*)&father1 + 2 << endl;system("pause");
}

定义了两个对象,分别看两个对象的虚函数表地址是否正确,发现两个类对象虚函数表地址相同。

以下为输出:

  类对象地址:0020F9C8虚函数表地址: 00B37894虚函数FatherFun1地址:00B37894虚函数FatherFun2地址:00B37898虚函数FatherFun3地址:00B3789C第二个类对象类对象地址:0020F9BC虚函数表地址: 00B37894虚函数FatherFun1地址:00B37894虚函数FatherFun2地址:00B37898虚函数FatherFun3地址:00B3789C请按任意键继续. . .

由此可见,第二点现在已经确认

3.测试类中无虚函数,是否存在虚函数表

#include <stdio.h>
#include <stdlib.h>
#include <iostream>using namespace std;class Test
{void TestFun1() {cout << "TestFun1" <<endl;}void TestFun2() {cout << "TestFun2" <<endl;}void TestFun3() {cout << "TestFun3" <<endl;}
};typedef void (*Fun)(void);int main()
{Test test;cout << "类对象地址:" << &test << endl;cout << "虚函数表地址: " << (int*)*(int*)&test << endl;cout << "虚函数TestFun1地址:" <<(int*)*(int*)&test << endl;cout << "虚函数TestFun2地址:" <<(int*)*(int*)&test + 1 << endl;cout << "虚函数TestFun3地址:" <<(int*)*(int*)&test + 2 << endl;system("pause");
}

以下为输出:

  类对象地址:0041FCEB虚函数表地址: CCCCCCCC虚函数TestFun1地址:CCCCCCCC虚函数TestFun2地址:CCCCCCD0虚函数TestFun3地址:CCCCCCD4请按任意键继续. . .

由此可见虚函数表地址为错误,第一条确认

4.子类继承父类,但不继承虚函数表

#include <stdio.h>
#include <stdlib.h>
#include <iostream>using namespace std;class Father
{virtual void FatherFun1() {cout << "FatherFun1" <<endl;}virtual void FatherFun2() {cout << "FatherFun2" <<endl;}virtual void FatherFun3() {cout << "FatherFun3" <<endl;}
};class Son : public Father
{virtual void SonFun1() {cout << "SonFun1" <<endl;}virtual void SonFun2() {cout << "SonFun2" <<endl;}virtual void SonFun3() {cout << "SonFun3" <<endl;}
};typedef void (*Fun)(void);int main()
{Father father;cout << "类对象地址:" << &father << endl;cout << "虚函数表地址: " << (int*)*(int*)&father << endl;cout << "虚函数FatherFun1地址:" <<(int*)*(int*)&father << endl;cout << "虚函数FatherFun2地址:" <<(int*)*(int*)&father + 1 << endl;cout << "虚函数FatherFun3地址:" <<(int*)*(int*)&father + 2 << endl;//cout << "虚函数sonFun1地址:" <<(int*)*(int*)&father + 3 << endl;//cout << "虚函数sonFun2地址:" <<(int*)*(int*)&father + 4 << endl;//cout << "虚函数sonFun3地址:" <<(int*)*(int*)&father + 5 << endl;Fun fun = (Fun)*(int*)*(int*)&father;fun();fun = (Fun)*((int*)*(int*)(&father) + 1);fun();fun = (Fun)*((int*)*(int*)(&father) + 2);fun();//fun = (Fun)*((int*)*(int*)(&father) + 3);//fun();//fun = (Fun)*((int*)*(int*)(&father) + 4);//fun();//fun = (Fun)*((int*)*(int*)(&father) + 5);//fun();cout << "----------------测试子类------------------" << endl;Son son;cout << "类对象地址:" << &son << endl;cout << "虚函数表地址: " << (int*)*(int*)&son << endl;cout << "虚函数继承FatherFun1地址:" <<(int*)*(int*)&son << endl;cout << "虚函数继承FatherFun2地址:" <<(int*)*(int*)&son + 1 << endl;cout << "虚函数继承FatherFun3地址:" <<(int*)*(int*)&son + 2 << endl;cout << "虚函数sonFun1地址:" <<(int*)*(int*)&son + 3 << endl;cout << "虚函数sonFun2地址:" <<(int*)*(int*)&son + 4 << endl;cout << "虚函数sonFun3地址:" <<(int*)*(int*)&son + 5 << endl;fun = (Fun)*(int*)*(int*)&son;fun();fun = (Fun)*((int*)*(int*)(&son) + 1);fun();fun = (Fun)*((int*)*(int*)(&son) + 2);fun();fun = (Fun)*((int*)*(int*)(&son) + 3);fun();fun = (Fun)*((int*)*(int*)(&son) + 4);fun();fun = (Fun)*((int*)*(int*)(&son) + 5);fun();system("pause");
}

如果将代码中注释代码给恢复,会直接发生段错误。

以下为输出结果:

类对象地址:0027FCA8
虚函数表地址: 01317930
虚函数FatherFun1地址:01317930
虚函数FatherFun2地址:01317934
虚函数FatherFun3地址:01317938
FatherFun1
FatherFun2
FatherFun3
----------------测试子类------------------
类对象地址:0027FC90
虚函数表地址: 01317974
虚函数继承FatherFun1地址:01317974
虚函数继承FatherFun2地址:01317978
虚函数继承FatherFun3地址:0131797C
虚函数sonFun1地址:01317980
虚函数sonFun2地址:01317984
虚函数sonFun3地址:01317988
FatherFun1
FatherFun2
FatherFun3
SonFun1
SonFun2
SonFun3
请按任意键继续. . .

由输出结果我们可以看到,父类和子类中的虚函数表地址是不一样的,而且子类继承了父类的虚函数,但是其地址是和父类中不一样的!。第四点确认!
并且我们根据输出可以发现,子类虚函数表中虚函数地址排序为先是继承的父类的函数,再是子类中的虚函数。

5.子类重写父类中虚函数,或子类重定义父类虚函数

#include <stdio.h>
#include <stdlib.h>
#include <iostream>using namespace std;class Father
{virtual void FatherFun4() {cout << "FatherFun4" <<endl;}virtual void FatherFun1() {cout << "FatherFun1" <<endl;}virtual void FatherFun2() {cout << "FatherFun2" <<endl;}virtual void FatherFun3() {cout << "FatherFun3" <<endl;}
};class Son : public Father
{virtual void SonFun1() {cout << "SonFun1" <<endl;}virtual void SonFun2() {cout << "SonFun2" <<endl;}virtual void SonFun3() {cout << "SonFun3" <<endl;}virtual void FatherFun4() {cout << "SonGetFatherFun4" <<endl;}virtual void FatherFun4(int a = 0) {cout << "SonGetFatherFun4 diffrent param" <<endl;}
};typedef void (*Fun)(void);
typedef void (*FunParam)(int);int main()
{
#if 1Father father;cout << "类对象地址:" << &father << endl;cout << "虚函数表地址: " << (int*)*(int*)&father << endl;cout << "虚函数FatherFun4地址:" <<(int*)*(int*)&father << endl;cout << "虚函数FatherFun1地址:" <<(int*)*(int*)&father + 1 << endl;cout << "虚函数FatherFun2地址:" <<(int*)*(int*)&father + 2 << endl;cout << "虚函数FatherFun3地址:" <<(int*)*(int*)&father + 3 << endl;Fun fun = (Fun)*(int*)*(int*)&father;fun();fun = (Fun)*((int*)*(int*)(&father) + 1);fun();fun = (Fun)*((int*)*(int*)(&father) + 2);fun();fun = (Fun)*((int*)*(int*)(&father) + 3);fun();cout << "----------------测试子类------------------" << endl;Son son;cout << "类对象地址:" << &son << endl;cout << "虚函数表地址: " << (int*)*(int*)&son << endl;cout << "虚函数继承SonGetFatherFun4地址:" <<(int*)*(int*)&son << endl;cout << "虚函数继承FatherFun1地址:" <<(int*)*(int*)&son + 1 << endl;cout << "虚函数继承FatherFun2地址:" <<(int*)*(int*)&son + 2 << endl;cout << "虚函数继承FatherFun3地址:" <<(int*)*(int*)&son + 3 << endl;cout << "虚函数sonFun1地址:" <<(int*)*(int*)&son + 4 << endl;cout << "虚函数sonFun2地址:" <<(int*)*(int*)&son + 5 << endl;cout << "虚函数sonFun3地址:" <<(int*)*(int*)&son + 6 << endl;cout << "虚函数SonGetFatherFun4 diffrent param地址:" <<(int*)*(int*)&son + 7 << endl;fun = (Fun)*(int*)*(int*)&son;fun();fun = (Fun)*((int*)*(int*)(&son) + 1);fun();fun = (Fun)*((int*)*(int*)(&son) + 2);fun();fun = (Fun)*((int*)*(int*)(&son) + 3);fun();fun = (Fun)*((int*)*(int*)(&son) + 4);fun();fun = (Fun)*((int*)*(int*)(&son) + 5);fun();fun = (Fun)*((int*)*(int*)(&son) + 6);fun();FunParam funParam= (FunParam)*((int*)*(int*)(&son) + 7);funParam(0);
#endifsystem("pause");
}

我们故意将父类中FatherFun4放在最前,而子类中的重写和重定义的FatherFun4 函数放在最后,看一下虚函数表中虚函数排放顺序是否有发生改变。

以下为输出结果:

  类对象地址:0021FD4C虚函数表地址: 011479B8虚函数FatherFun4地址:011479B8虚函数FatherFun1地址:011479BC虚函数FatherFun2地址:011479C0虚函数FatherFun3地址:011479C4FatherFun4FatherFun1FatherFun2FatherFun3----------------测试子类------------------类对象地址:0021FD34虚函数表地址: 01147A10虚函数继承SonGetFatherFun4地址:01147A10虚函数继承FatherFun1地址:01147A14虚函数继承FatherFun2地址:01147A18虚函数继承FatherFun2地址:01147A1C虚函数sonFun1地址:01147A20虚函数sonFun2地址:01147A24虚函数sonFun3地址:01147A28虚函数SonGetFatherFun4 diffrent param地址:01147A2C**SonGetFatherFun4**FatherFun1FatherFun2FatherFun3SonFun1SonFun2SonFun3SonGetFatherFun4 diffrent param

我们可以清楚的看到,位于子类最后函数重写的FatherFun4被放在了本该继承的父类FatherFun4位置上(先输出的是SonGetFatherFun4),而函数重定义则没有发生改变。

由此可以得出结论:

(1)覆盖的FatherFun4函数被放到了虚函数表中原父类虚函数的位置

(2)没有被覆盖的函数没有变化

6.子类指针指向父类

#include <stdio.h>
#include <stdlib.h>
#include <iostream>using namespace std;class Father
{virtual void FatherFun1() {cout << "FatherFun1" <<endl;}virtual void FatherFun2() {cout << "FatherFun2" <<endl;}virtual void FatherFun3() {cout << "FatherFun3" <<endl;}
};class Son : public Father
{virtual void SonFun1() {cout << "SonFun1" <<endl;}virtual void SonFun2() {cout << "SonFun2" <<endl;}virtual void SonFun3() {cout << "SonFun3" <<endl;}
};#if 0
class Test
{void TestFun1() {cout << "TestFun1" <<endl;}void TestFun2() {cout << "TestFun2" <<endl;}void TestFun3() {cout << "TestFun3" <<endl;}
};
#endiftypedef void (*Fun)(void);
typedef void (*FunParam)(int);int main()
{cout << "----------------测试父类------------------" << endl;Father father;cout << "类对象地址:" << &father << endl;cout << "虚函数表地址: " << (int*)*(int*)&father << endl;cout << "虚函数FatherFun1地址:" <<(int*)*(int*)&father << endl;cout << "虚函数FatherFun1地址:" <<(int*)*(int*)&father + 1 << endl;cout << "虚函数FatherFun2地址:" <<(int*)*(int*)&father + 2 << endl;Fun fun = (Fun)*(int*)*(int*)&father;fun();fun = (Fun)*((int*)*(int*)(&father) + 1);fun();fun = (Fun)*((int*)*(int*)(&father) + 2);fun();cout << "----------------测试子类------------------" << endl;Son son;cout << "类对象地址:" << &son << endl;cout << "虚函数表地址: " << (int*)*(int*)&son << endl;cout << "虚函数继承FatherFun1地址:" <<(int*)*(int*)&son << endl;cout << "虚函数继承FatherFun2地址:" <<(int*)*(int*)&son + 1 << endl;cout << "虚函数继承FatherFun3地址:" <<(int*)*(int*)&son + 2 << endl;cout << "虚函数sonFun1地址:" <<(int*)*(int*)&son + 3 << endl;cout << "虚函数sonFun2地址:" <<(int*)*(int*)&son + 4 << endl;cout << "虚函数sonFun3地址:" <<(int*)*(int*)&son + 5 << endl;fun = (Fun)*(int*)*(int*)&son;fun();fun = (Fun)*((int*)*(int*)(&son) + 1);fun();fun = (Fun)*((int*)*(int*)(&son) + 2);fun();fun = (Fun)*((int*)*(int*)(&son) + 3);fun();fun = (Fun)*((int*)*(int*)(&son) + 4);fun();fun = (Fun)*((int*)*(int*)(&son) + 5);fun();cout << "----------------测试父类指针指向子类------------------" << endl;Father* pointSon = new Son;cout << "类对象地址:" << pointSon << endl;cout << "虚函数表地址: " << (int*)*(int*)pointSon << endl;cout << "虚函数继承FatherFun1地址:" <<(int*)*(int*)pointSon << endl;cout << "虚函数继承FatherFun2地址:" <<(int*)*(int*)pointSon + 1 << endl;cout << "虚函数继承FatherFun3地址:" <<(int*)*(int*)pointSon + 2 << endl;cout << "虚函数sonFun1地址:" <<(int*)*(int*)pointSon + 3 << endl;cout << "虚函数sonFun2地址:" <<(int*)*(int*)pointSon + 4 << endl;cout << "虚函数sonFun3地址:" <<(int*)*(int*)pointSon + 5 << endl;fun = (Fun)*(int*)*(int*)pointSon;fun();fun = (Fun)*((int*)*(int*)(pointSon) + 1);fun();fun = (Fun)*((int*)*(int*)(pointSon) + 2);fun();fun = (Fun)*((int*)*(int*)(pointSon) + 3);fun();fun = (Fun)*((int*)*(int*)(pointSon) + 4);fun();fun = (Fun)*((int*)*(int*)(pointSon) + 5);fun();system("pause");
}

实际上父类指针指向子类,调用的是子类的虚函数表。

以下为输出:

----------------测试父类------------------
类对象地址:0029FDD0
虚函数表地址: 000F89BC
虚函数FatherFun1地址:000F89BC
虚函数FatherFun1地址:000F89C0
虚函数FatherFun2地址:000F89C4
FatherFun1
FatherFun2
FatherFun3
----------------测试子类------------------
类对象地址:0029FDB8
虚函数表地址: 000F8A00
虚函数继承FatherFun1地址:000F8A00
虚函数继承FatherFun2地址:000F8A04
虚函数继承FatherFun3地址:000F8A08
虚函数sonFun1地址:000F8A0C
虚函数sonFun2地址:000F8A10
虚函数sonFun3地址:000F8A14
FatherFun1
FatherFun2
FatherFun3
SonFun1
SonFun2
SonFun3
----------------测试父类指针指向子类------------------
类对象地址:003B55D8
虚函数表地址: 000F8A00
虚函数继承FatherFun1地址:000F8A00
虚函数继承FatherFun2地址:000F8A04
虚函数继承FatherFun3地址:000F8A08
虚函数sonFun1地址:000F8A0C
虚函数sonFun2地址:000F8A10
虚函数sonFun3地址:000F8A14
FatherFun1
FatherFun2
FatherFun3
SonFun1
SonFun2
SonFun3
请按任意键继续. . .

由虚函数表地址我们就可以看到,父类指针指向子类的时候,其虚函数表地址和子类虚函数表地址是一样的。由此,第五点确认!

7.子类重写父类虚函数,并子类指针指向父类

#include <stdio.h>
#include <stdlib.h>
#include <iostream>using namespace std;class Father
{virtual void FatherFun4() {cout << "FatherFun4" <<endl;}virtual void FatherFun1() {cout << "FatherFun1" <<endl;}virtual void FatherFun2() {cout << "FatherFun2" <<endl;}virtual void FatherFun3() {cout << "FatherFun3" <<endl;}
};class Son : public Father
{virtual void SonFun1() {cout << "SonFun1" <<endl;}virtual void SonFun2() {cout << "SonFun2" <<endl;}virtual void SonFun3() {cout << "SonFun3" <<endl;}virtual void FatherFun4() {cout << "SonGetFatherFun4" <<endl;}
};#if 0
class Test
{void TestFun1() {cout << "TestFun1" <<endl;}void TestFun2() {cout << "TestFun2" <<endl;}void TestFun3() {cout << "TestFun3" <<endl;}
};
#endiftypedef void (*Fun)(void);
typedef void (*FunParam)(int);int main()
{cout << "----------------测试父类------------------" << endl;Father father;cout << "类对象地址:" << &father << endl;cout << "虚函数表地址: " << (int*)*(int*)&father << endl;cout << "虚函数FatherFun4地址:" <<(int*)*(int*)&father << endl;cout << "虚函数FatherFun1地址:" <<(int*)*(int*)&father + 1 << endl;cout << "虚函数FatherFun2地址:" <<(int*)*(int*)&father + 2 << endl;cout << "虚函数FatherFun3地址:" <<(int*)*(int*)&father + 3 << endl;Fun fun = (Fun)*(int*)*(int*)&father;fun();fun = (Fun)*((int*)*(int*)(&father) + 1);fun();fun = (Fun)*((int*)*(int*)(&father) + 2);fun();fun = (Fun)*((int*)*(int*)(&father) + 3);fun();cout << "----------------测试子类------------------" << endl;Son son;cout << "类对象地址:" << &son << endl;cout << "虚函数表地址: " << (int*)*(int*)&son << endl;cout << "虚函数继承FatherFun4地址:" <<(int*)*(int*)&son << endl;cout << "虚函数继承FatherFun1地址:" <<(int*)*(int*)&son + 1 << endl;cout << "虚函数继承FatherFun2地址:" <<(int*)*(int*)&son + 2 << endl;cout << "虚函数继承FatherFun3地址:" <<(int*)*(int*)&son + 3 << endl;cout << "虚函数sonFun1地址:" <<(int*)*(int*)&son + 4 << endl;cout << "虚函数sonFun2地址:" <<(int*)*(int*)&son + 5 << endl;cout << "虚函数sonFun3地址:" <<(int*)*(int*)&son + 6 << endl;fun = (Fun)*(int*)*(int*)&son;fun();fun = (Fun)*((int*)*(int*)(&son) + 1);fun();fun = (Fun)*((int*)*(int*)(&son) + 2);fun();fun = (Fun)*((int*)*(int*)(&son) + 3);fun();fun = (Fun)*((int*)*(int*)(&son) + 4);fun();fun = (Fun)*((int*)*(int*)(&son) + 5);fun();fun = (Fun)*((int*)*(int*)(&son) + 6);fun();cout << "----------------测试父类指针指向子类------------------" << endl;Father* pointSon = new Son;cout << "类对象地址:" << pointSon << endl;cout << "虚函数表地址: " << (int*)*(int*)pointSon << endl;cout << "虚函数继承FatherFun1地址:" <<(int*)*(int*)pointSon << endl;cout << "虚函数继承FatherFun2地址:" <<(int*)*(int*)pointSon + 1 << endl;cout << "虚函数继承FatherFun3地址:" <<(int*)*(int*)pointSon + 2 << endl;cout << "虚函数sonFun1地址:" <<(int*)*(int*)pointSon + 3 << endl;cout << "虚函数sonFun2地址:" <<(int*)*(int*)pointSon + 4 << endl;cout << "虚函数sonFun3地址:" <<(int*)*(int*)pointSon + 5 << endl;fun = (Fun)*(int*)*(int*)pointSon;fun();fun = (Fun)*((int*)*(int*)(pointSon) + 1);fun();fun = (Fun)*((int*)*(int*)(pointSon) + 2);fun();fun = (Fun)*((int*)*(int*)(pointSon) + 3);fun();fun = (Fun)*((int*)*(int*)(pointSon) + 4);fun();fun = (Fun)*((int*)*(int*)(pointSon) + 5);fun();fun = (Fun)*((int*)*(int*)(pointSon) + 6);fun();system("pause");
}

直接看输出结果:

    ----------------测试父类------------------类对象地址:0034F788虚函数表地址: 000B8A14虚函数FatherFun4地址:000B8A14虚函数FatherFun1地址:000B8A18虚函数FatherFun2地址:000B8A1C虚函数FatherFun3地址:000B8A20FatherFun4FatherFun1FatherFun2FatherFun3----------------测试子类------------------类对象地址:0034F770虚函数表地址: 000B8A6C虚函数继承FatherFun4地址:000B8A6C虚函数继承FatherFun1地址:000B8A70虚函数继承FatherFun2地址:000B8A74虚函数继承FatherFun3地址:000B8A78虚函数sonFun1地址:000B8A7C虚函数sonFun2地址:000B8A80虚函数sonFun3地址:000B8A84SonGetFatherFun4FatherFun1FatherFun2FatherFun3SonFun1SonFun2SonFun3----------------测试父类指针指向子类------------------类对象地址:005855D8虚函数表地址: 000B8A6C虚函数继承FatherFun1地址:000B8A6C虚函数继承FatherFun2地址:000B8A70虚函数继承FatherFun3地址:000B8A74虚函数sonFun1地址:000B8A78虚函数sonFun2地址:000B8A7C虚函数sonFun3地址:000B8A80SonGetFatherFun4FatherFun1FatherFun2FatherFun3SonFun1SonFun2SonFun3请按任意键继续. . .

实际上和第六点结果是一样的。

结论

如果对您有所帮助,请点个赞吧!

虚函数表构成、地址详细说明相关推荐

  1. C++对象的内存布局1---基础篇----C++ 虚函数表解析

    [-] 前言 虚函数表 一般继承(无虚函数覆盖) 一般继承(有虚函数覆盖) 多重继承(无虚函数覆盖) 多重继承(有虚函数覆盖) 安全性 结束语 附录一:VC中查看虚函数表 附录 二:例程 前言 C++ ...

  2. 虚函数表剖析,网上转的,呵呵

    http://www.cppblog.com/xczhang/archive/2008/01/20/41508.html C++虚函数表解析(转) C++中的虚函数的作用主要是实现了多态的机制.关于多 ...

  3. C++ 虚函数表解析

    转载自 https://blog.csdn.net/zhou191954/article/details/44919479 C++ 虚函数表解析 前言 C++中的虚函数的作用主要是实现了多态的机制.关 ...

  4. C++虚函数表解析(转) ——写的真不错

    C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有"多种形态" ...

  5. 深入理解C++ 虚函数表

    目录 深入理解C++ 虚函数表 虚函数表概述 单继承下的虚函数表 派生类未覆盖基类虚函数 派生类覆盖基类虚函数 多继承下的虚函数表 无虚函数覆盖 派生类覆盖基类虚函数 钻石型虚继承 总结 几个原则 安 ...

  6. C++ 虚函数表解析 继承

    C++ 虚函数表解析 陈皓 http://blog.csdn.net/haoel 前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父 ...

  7. C++ 虚函数表解析(转)

    前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有"多种形态&q ...

  8. C++如何获取虚函数表(vtbl)的内容及虚成员函数指针存放原理

    一.前言 因为不同的运行环境的运行结果是不同的,特别是不同的编译器对c++类对象模型的实现是很可能存在差异,所以有时不同的编译平台的代码不能兼容也是部分原因于此.本文的运行环境是: ubuntu16. ...

  9. C++虚函数表解析 (Lawliet 修改+注释版)(附有部分网友的重要评论)

    C++ 虚函数表解析   2008-11-14 作者:陈皓 来源:csdn     前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型的指针指向其子类的实例,然后通过父 ...

  10. 基本语言细节---C++ 虚函数表解析 陈皓

    C++ 虚函数表解析 陈皓 http://blog.csdn.net/haoel 前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父 ...

最新文章

  1. mysql 被关闭了_mysql被关闭简析
  2. java提取多行嵌套div/div内容的正则表达式_提取某一段div标签之间内容的正则表达式怎么写...
  3. mpandroidchart 设置x轴数据_跟小白学Python数据分析——绘制条形图
  4. 复制构造函数被调用的3种情况
  5. 追忆我的2008-养成做笔记的习惯
  6. C# 仿windows资源管理器
  7. android切图双数,UI切图与命名规范
  8. 14565B简单使用教程
  9. php查询qq等级,php仿QQ等级太阳显示函数_php
  10. python获取图像灰度极值点_opencv-python读取tiff影像上任意点的灰度值和RBG值
  11. 【原创】OpenDDS笔记(一) Windows环境下的开发实例
  12. plt如何随心所欲的更改x轴坐标
  13. 微信分享功能踩坑过程
  14. CTF之crpto练习三
  15. Xcode 官方下载地址 https://developer.apple.com/downloads/
  16. 投资理财-简单策略其实不简单
  17. 红米redmi X系列和荣耀智慧屏X1哪个好
  18. 大白话5分钟带你走进人工智能-第二十八节集成学习之随机森林概念介绍(1)
  19. XXTea 加密/解密 字符串
  20. arcgis直方图导出地图_ArcGIS教程地图导出花式教你如何选择

热门文章

  1. java实现ftl文件转图片
  2. linux开发板访问互联网 笔记本win10中虚拟机
  3. 2021年电工(初级)考试试卷及电工(初级)考试平台
  4. 052: 单调性与极值及凹凸性之型三函数零点;渐近线
  5. hdu 5053 the Sum of Cube(水)
  6. 【UNIX网络编程】|【07】SCTP协议探究
  7. 利用Python爬虫和Tableau分析链家网二手房信息
  8. word文档的尺寸和字号对照表
  9. qt.qpa.plugin: Could not load the Qt platform plugin “xcb“ in问题
  10. 三菱PLC进行连续数据采集、时序和故障追踪的方法