参考博文:c++虚函数表、地址详解-CSDN博客
本文在上述博文的基础上,补充了x64下的验证代码。
一.什么是虚函数表,它有什么特点?
虚函数大家都知道是基本用于实现多态的,当父类指针指向子类对象的时候,如何确定调用的函数是父类里的还是子类里面的,这就要用到虚函数表。下面一点点表诉什么是虚函数表,和虚函数表的特点。如有说错的地方,欢迎指正:
1.编译器会为每个有虚函数的类创建一个虚函数表
如有类中没有虚函数,那么这个虚函数表就不存在,而不是表中无数据。同时,有虚函数的类都会有自己的虚函数表,一个类不会有另外一个类的虚函数表,包括两个类属于继承关系。
2.虚函数表会被一个类的所有对象所拥有
类的每个虚函数成员占据虚函数表的一行,所以说,如果类中有N个虚函数,那么该虚函数表将会有N*8的大小(x64)。并不是每个类对象都会有自己的表。
3.编译器会将虚函数表指针存放在类对象最前面的位置
对于类的每个对象,编译器都会为其生成一个透明不可见的指针,这个指针就是虚函数表指针,存放在该对象内存的最前位置。例如:一个类拥有虚函数表,类对象内存布局中前8个字节就是虚函数表的地址(64位)。这个接下来我们会进行测试。
4.延伸,由第一条可知,子类继承父类,其虚函数表和表函数地址是不一样的。
5.父类指针指向子类对象时,调用时实际上是根据子类对象的虚函数表进行查找。
6.如果父类有虚函数,子类没有定义虚函数,那么子类也会有虚函数表。
二.测试
1.测试虚函数表地址和虚函数地址
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#ifdef _WIN64
#define PTR_VAL int64_t
#else
#define PTR_VAL int32_t
#endif
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 << "虚函数表地址: " << (PTR_VAL*)*(PTR_VAL*)&father << endl;
cout << "虚函数FatherFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&father << endl;
cout << "虚函数FatherFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&father + 1 << endl;
cout << "虚函数FatherFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&father + 2 << endl;
cout << "测试地址是否正确" << endl;
Fun fun = (Fun) * (PTR_VAL*)*(PTR_VAL*)&father;
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&father) + 1);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&father) + 2);
fun();
system("pause");
}
上面说过, x64下,类对象内存中前8个字节就是虚函数表的地址,那么我们获取类对象前8个字节,(int64_t)&father就是虚函数表地址,我们再给他转换成地址指针为(int64_t*)(int64_t)&father。然后我们在看一下输出结果:
类对象地址:000000ADA0B2F768
虚函数表地址: 00007FF7FEAABCB0
虚函数FatherFun1地址:00007FF7FEAABCB0
虚函数FatherFun2地址:00007FF7FEAABCB8
虚函数FatherFun3地址:00007FF7FEAABCC0
测试地址是否正确
FatherFun1
FatherFun2
FatherFun3
请按任意键继续. . .
从这个输出我们可以看到,FatherFun1、FatherFun2、FatherFun3的地址只差了8个字节,且输出是正确的,那么第三点已确认!
2.多个类对象的虚函数表地址
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#ifdef _WIN64
#define PTR_VAL int64_t
#else
#define PTR_VAL int32_t
#endif
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 << "虚函数表地址: " << (PTR_VAL*)*(PTR_VAL*)&father << endl;
cout << "虚函数FatherFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&father << endl;
cout << "虚函数FatherFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&father + 1 << endl;
cout << "虚函数FatherFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&father + 2 << endl;
cout << "第二个类对象" << endl;
Father father1;
cout << "类对象地址:" << &father1 << endl;
cout << "虚函数表地址: " << (PTR_VAL*)*(PTR_VAL*)&father1 << endl;
cout << "虚函数FatherFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&father1 << endl;
cout << "虚函数FatherFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&father1 + 1 << endl;
cout << "虚函数FatherFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&father1 + 2 << endl;
system("pause");
}
定义了两个对象,分别看两个对象的虚函数表地址是否正确,发现两个类对象虚函数表地址相同。
以下为输出:
类对象地址:00000070C3DCFC18
虚函数表地址: 00007FF775FCBCF8
虚函数FatherFun1地址:00007FF775FCBCF8
虚函数FatherFun2地址:00007FF775FCBD00
虚函数FatherFun3地址:00007FF775FCBD08
第二个类对象
类对象地址:00000070C3DCFC38
虚函数表地址: 00007FF775FCBCF8
虚函数FatherFun1地址:00007FF775FCBCF8
虚函数FatherFun2地址:00007FF775FCBD00
虚函数FatherFun3地址:00007FF775FCBD08
请按任意键继续. . .
由此可见,第二点现在已经确认!
3.测试类中无虚函数,是否存在虚函数表
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#ifdef _WIN64
#define PTR_VAL int64_t
#else
#define PTR_VAL int32_t
#endif
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 << "虚函数表地址: " << (PTR_VAL*)*(PTR_VAL*)&test << endl;
cout << "虚函数TestFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&test << endl;
cout << "虚函数TestFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&test + 1 << endl;
cout << "虚函数TestFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&test + 2 << endl;
system("pause");
}
以下为输出:
类对象地址:000000AEBF9DFB44
虚函数表地址: CCCCCCCCCCCCCCCC
虚函数TestFun1地址:CCCCCCCCCCCCCCCC
虚函数TestFun2地址:CCCCCCCCCCCCCCD4
虚函数TestFun3地址:CCCCCCCCCCCCCCDC
请按任意键继续. . .
由此可见虚函数表地址为错误,第一条确认!
4.子类继承父类,但不继承虚函数表
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#ifdef _WIN64
#define PTR_VAL int64_t
#else
#define PTR_VAL int32_t
#endif
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 << "虚函数表地址: " << (PTR_VAL*)*(PTR_VAL*)&father << endl;
cout << "虚函数FatherFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&father << endl;
cout << "虚函数FatherFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&father + 1 << endl;
cout << "虚函数FatherFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&father + 2 << endl;
//cout << "虚函数sonFun1地址:" <<(PTR_VAL*)*(PTR_VAL*)&father + 3 << endl;
//cout << "虚函数sonFun2地址:" <<(PTR_VAL*)*(PTR_VAL*)&father + 4 << endl;
//cout << "虚函数sonFun3地址:" <<(PTR_VAL*)*(PTR_VAL*)&father + 5 << endl;
Fun fun = (Fun) * (PTR_VAL*)*(PTR_VAL*)&father;
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&father) + 1);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&father) + 2);
fun();
//fun = (Fun)*((PTR_VAL*)*(PTR_VAL*)(&father) + 3);
//fun();
//fun = (Fun)*((PTR_VAL*)*(PTR_VAL*)(&father) + 4);
//fun();
//fun = (Fun)*((PTR_VAL*)*(PTR_VAL*)(&father) + 5);
//fun();
cout << "----------------测试子类------------------" << endl;
Son son;
cout << "类对象地址:" << &son << endl;
cout << "虚函数表地址: " << (PTR_VAL*)*(PTR_VAL*)&son << endl;
cout << "虚函数继承FatherFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&son << endl;
cout << "虚函数继承FatherFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 1 << endl;
cout << "虚函数继承FatherFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 2 << endl;
cout << "虚函数sonFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 3 << endl;
cout << "虚函数sonFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 4 << endl;
cout << "虚函数sonFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 5 << endl;
fun = (Fun) * (PTR_VAL*)*(PTR_VAL*)&son;
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 1);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 2);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 3);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 4);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 5);
fun();
system("pause");
}
如果将代码中注释代码给恢复,会直接发生段错误。
以下为输出结果:
类对象地址:000000A9936FF9A8
虚函数表地址: 00007FF667CABCF8
虚函数FatherFun1地址:00007FF667CABCF8
虚函数FatherFun2地址:00007FF667CABD00
虚函数FatherFun3地址:00007FF667CABD08
FatherFun1
FatherFun2
FatherFun3
----------------测试子类------------------
类对象地址:000000A9936FF9E8
虚函数表地址: 00007FF667CABD50
虚函数继承FatherFun1地址:00007FF667CABD50
虚函数继承FatherFun2地址:00007FF667CABD58
虚函数继承FatherFun3地址:00007FF667CABD60
虚函数sonFun1地址:00007FF667CABD68
虚函数sonFun2地址:00007FF667CABD70
虚函数sonFun3地址:00007FF667CABD78
FatherFun1
FatherFun2
FatherFun3
SonFun1
SonFun2
SonFun3
请按任意键继续. . .
由输出结果我们可以看到,父类和子类中的虚函数表地址是不一样的,而且子类继承了父类的虚函数,但是其地址是和父类中不一样的!。第四点确认!
并且我们根据输出可以发现,子类虚函数表中虚函数地址排序为先是继承的父类的函数,再是子类中的虚函数。
5.子类重写父类中虚函数,或子类重定义父类虚函数
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#ifdef _WIN64
#define PTR_VAL int64_t
#else
#define PTR_VAL int32_t
#endif
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 1
Father father;
cout << "类对象地址:" << &father << endl;
cout << "虚函数表地址: " << (PTR_VAL*)*(PTR_VAL*)&father << endl;
cout << "虚函数FatherFun4地址:" << (PTR_VAL*)*(PTR_VAL*)&father << endl;
cout << "虚函数FatherFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&father + 1 << endl;
cout << "虚函数FatherFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&father + 2 << endl;
cout << "虚函数FatherFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&father + 3 << endl;
Fun fun = (Fun) * (PTR_VAL*)*(PTR_VAL*)&father;
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&father) + 1);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&father) + 2);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&father) + 3);
fun();
cout << "----------------测试子类------------------" << endl;
Son son;
cout << "类对象地址:" << &son << endl;
cout << "虚函数表地址: " << (PTR_VAL*)*(PTR_VAL*)&son << endl;
cout << "虚函数继承SonGetFatherFun4地址:" << (PTR_VAL*)*(PTR_VAL*)&son << endl;
cout << "虚函数继承FatherFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 1 << endl;
cout << "虚函数继承FatherFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 2 << endl;
cout << "虚函数继承FatherFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 3 << endl;
cout << "虚函数sonFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 4 << endl;
cout << "虚函数sonFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 5 << endl;
cout << "虚函数sonFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 6 << endl;
cout << "虚函数SonGetFatherFun4 diffrent param地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 7 << endl;
fun = (Fun) * (PTR_VAL*)*(PTR_VAL*)&son;
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 1);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 2);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 3);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 4);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 5);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 6);
fun();
FunParam funParam = (FunParam) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 7);
funParam(0);
#endif
system("pause");
}
我们故意将父类中FatherFun4放在最前,而子类中的重写和重定义的FatherFun4 函数放在最后,看一下虚函数表中虚函数排放顺序是否有发生改变。
以下为输出结果:
虚函数FatherFun1地址:00007FF76199BD00
虚函数FatherFun2地址:00007FF76199BD08
虚函数FatherFun3地址:00007FF76199BD10
FatherFun4
FatherFun1
FatherFun2
FatherFun3
----------------测试子类------------------
类对象地址:0000003360F5F648
虚函数表地址: 00007FF76199BD68
虚函数继承SonGetFatherFun4地址:00007FF76199BD68
虚函数继承FatherFun1地址:00007FF76199BD70
虚函数继承FatherFun2地址:00007FF76199BD78
虚函数继承FatherFun3地址:00007FF76199BD80
虚函数sonFun1地址:00007FF76199BD88
虚函数sonFun2地址:00007FF76199BD90
虚函数sonFun3地址:00007FF76199BD98
虚函数SonGetFatherFun4 diffrent param地址:00007FF76199BDA0
SonGetFatherFun4
FatherFun1
FatherFun2
FatherFun3
SonFun1
SonFun2
SonFun3
SonGetFatherFun4 diffrent param
请按任意键继续. . .
我们可以清楚的看到,位于子类最后函数重写的FatherFun4被放在了本该继承的父类FatherFun4位置上(先输出的是SonGetFatherFun4),而函数重定义则没有发生改变。
由此可以得出结论:
(1)覆盖的FatherFun4函数被放到了虚函数表中原父类虚函数的位置
(2)没有被覆盖的函数没有变化
6.子类指针指向父类
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#ifdef _WIN64
#define PTR_VAL int64_t
#else
#define PTR_VAL int32_t
#endif
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; }
};
#endif
typedef void (*Fun)(void);
typedef void (*FunParam)(int);
int main()
{
cout << "----------------测试父类------------------" << endl;
Father father;
cout << "类对象地址:" << &father << endl;
cout << "虚函数表地址: " << (PTR_VAL*)*(PTR_VAL*)&father << endl;
cout << "虚函数FatherFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&father << endl;
cout << "虚函数FatherFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&father + 1 << endl;
cout << "虚函数FatherFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&father + 2 << endl;
Fun fun = (Fun) * (PTR_VAL*)*(PTR_VAL*)&father;
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&father) + 1);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&father) + 2);
fun();
cout << "----------------测试子类------------------" << endl;
Son son;
cout << "类对象地址:" << &son << endl;
cout << "虚函数表地址: " << (PTR_VAL*)*(PTR_VAL*)&son << endl;
cout << "虚函数继承FatherFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&son << endl;
cout << "虚函数继承FatherFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 1 << endl;
cout << "虚函数继承FatherFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 2 << endl;
cout << "虚函数sonFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 3 << endl;
cout << "虚函数sonFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 4 << endl;
cout << "虚函数sonFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 5 << endl;
fun = (Fun) * (PTR_VAL*)*(PTR_VAL*)&son;
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 1);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 2);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 3);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 4);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 5);
fun();
cout << "----------------测试父类指针指向子类------------------" << endl;
Father* pointSon = new Son;
cout << "类对象地址:" << pointSon << endl;
cout << "虚函数表地址: " << (PTR_VAL*)*(PTR_VAL*)pointSon << endl;
cout << "虚函数继承FatherFun1地址:" << (PTR_VAL*)*(PTR_VAL*)pointSon << endl;
cout << "虚函数继承FatherFun2地址:" << (PTR_VAL*)*(PTR_VAL*)pointSon + 1 << endl;
cout << "虚函数继承FatherFun3地址:" << (PTR_VAL*)*(PTR_VAL*)pointSon + 2 << endl;
cout << "虚函数sonFun1地址:" << (PTR_VAL*)*(PTR_VAL*)pointSon + 3 << endl;
cout << "虚函数sonFun2地址:" << (PTR_VAL*)*(PTR_VAL*)pointSon + 4 << endl;
cout << "虚函数sonFun3地址:" << (PTR_VAL*)*(PTR_VAL*)pointSon + 5 << endl;
fun = (Fun) * (PTR_VAL*)*(PTR_VAL*)pointSon;
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(pointSon)+1);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(pointSon)+2);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(pointSon)+3);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(pointSon)+4);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(pointSon)+5);
fun();
system("pause");
}
实际上父类指针指向子类,调用的是子类的虚函数表。
以下为输出:
类对象地址:00000058117AF688
虚函数表地址: 00007FF6F469CD50
虚函数继承FatherFun1地址:00007FF6F469CD50
虚函数继承FatherFun2地址:00007FF6F469CD58
虚函数继承FatherFun3地址:00007FF6F469CD60
虚函数sonFun1地址:00007FF6F469CD68
虚函数sonFun2地址:00007FF6F469CD70
虚函数sonFun3地址:00007FF6F469CD78
FatherFun1
FatherFun2
FatherFun3
SonFun1
SonFun2
SonFun3
----------------测试父类指针指向子类------------------
类对象地址:0000021C918185C0
虚函数表地址: 00007FF6F469CD50
虚函数继承FatherFun1地址:00007FF6F469CD50
虚函数继承FatherFun2地址:00007FF6F469CD58
虚函数继承FatherFun3地址:00007FF6F469CD60
虚函数sonFun1地址:00007FF6F469CD68
虚函数sonFun2地址:00007FF6F469CD70
虚函数sonFun3地址:00007FF6F469CD78
FatherFun1
FatherFun2
FatherFun3
SonFun1
SonFun2
SonFun3
请按任意键继续. . .
由虚函数表地址我们就可以看到,父类指针指向子类的时候,其虚函数表地址和子类虚函数表地址是一样的。由此,第五点确认。
7.子类重写父类虚函数,并父类指针指向子类
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#ifdef _WIN64
#define PTR_VAL int64_t
#else
#define PTR_VAL int32_t
#endif
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; }
};
#endif
typedef void (*Fun)(void);
typedef void (*FunParam)(int);
int main()
{
cout << "----------------测试父类------------------" << endl;
Father father;
cout << "类对象地址:" << &father << endl;
cout << "虚函数表地址: " << (PTR_VAL*)*(PTR_VAL*)&father << endl;
cout << "虚函数FatherFun4地址:" << (PTR_VAL*)*(PTR_VAL*)&father << endl;
cout << "虚函数FatherFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&father + 1 << endl;
cout << "虚函数FatherFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&father + 2 << endl;
cout << "虚函数FatherFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&father + 3 << endl;
Fun fun = (Fun) * (PTR_VAL*)*(PTR_VAL*)&father;
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&father) + 1);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&father) + 2);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&father) + 3);
fun();
cout << "----------------测试子类------------------" << endl;
Son son;
cout << "类对象地址:" << &son << endl;
cout << "虚函数表地址: " << (PTR_VAL*)*(PTR_VAL*)&son << endl;
cout << "虚函数继承FatherFun4地址:" << (PTR_VAL*)*(PTR_VAL*)&son << endl;
cout << "虚函数继承FatherFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 1 << endl;
cout << "虚函数继承FatherFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 2 << endl;
cout << "虚函数继承FatherFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 3 << endl;
cout << "虚函数sonFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 4 << endl;
cout << "虚函数sonFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 5 << endl;
cout << "虚函数sonFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 6 << endl;
fun = (Fun) * (PTR_VAL*)*(PTR_VAL*)&son;
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 1);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 2);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 3);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 4);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 5);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 6);
fun();
cout << "----------------测试父类指针指向子类------------------" << endl;
Father* pointSon = new Son;
cout << "类对象地址:" << pointSon << endl;
cout << "虚函数表地址: " << (PTR_VAL*)*(PTR_VAL*)pointSon << endl;
cout << "虚函数继承FatherFun1地址:" << (PTR_VAL*)*(PTR_VAL*)pointSon << endl;
cout << "虚函数继承FatherFun2地址:" << (PTR_VAL*)*(PTR_VAL*)pointSon + 1 << endl;
cout << "虚函数继承FatherFun3地址:" << (PTR_VAL*)*(PTR_VAL*)pointSon + 2 << endl;
cout << "虚函数sonFun1地址:" << (PTR_VAL*)*(PTR_VAL*)pointSon + 3 << endl;
cout << "虚函数sonFun2地址:" << (PTR_VAL*)*(PTR_VAL*)pointSon + 4 << endl;
cout << "虚函数sonFun3地址:" << (PTR_VAL*)*(PTR_VAL*)pointSon + 5 << endl;
fun = (Fun) * (PTR_VAL*)*(PTR_VAL*)pointSon;
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(pointSon)+1);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(pointSon)+2);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(pointSon)+3);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(pointSon)+4);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(pointSon)+5);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(pointSon)+6);
fun();
system("pause");
}
直接看输出结果:
----------------测试父类------------------
类对象地址:000000555C70FBF8
虚函数表地址: 00007FF61736CCF8
虚函数FatherFun4地址:00007FF61736CCF8
虚函数FatherFun1地址:00007FF61736CD00
虚函数FatherFun2地址:00007FF61736CD08
虚函数FatherFun3地址:00007FF61736CD10
FatherFun4
FatherFun1
FatherFun2
FatherFun3
----------------测试子类------------------
类对象地址:000000555C70FC38
虚函数表地址: 00007FF61736CD68
虚函数继承FatherFun4地址:00007FF61736CD68
虚函数继承FatherFun1地址:00007FF61736CD70
虚函数继承FatherFun2地址:00007FF61736CD78
虚函数继承FatherFun3地址:00007FF61736CD80
虚函数sonFun1地址:00007FF61736CD88
虚函数sonFun2地址:00007FF61736CD90
虚函数sonFun3地址:00007FF61736CD98
SonGetFatherFun4
FatherFun1
FatherFun2
FatherFun3
SonFun1
SonFun2
SonFun3
----------------测试父类指针指向子类------------------
类对象地址:0000019CE3F99140
虚函数表地址: 00007FF61736CD68
虚函数继承FatherFun1地址:00007FF61736CD68
虚函数继承FatherFun2地址:00007FF61736CD70
虚函数继承FatherFun3地址:00007FF61736CD78
虚函数sonFun1地址:00007FF61736CD80
虚函数sonFun2地址:00007FF61736CD88
虚函数sonFun3地址:00007FF61736CD90
SonGetFatherFun4
FatherFun1
FatherFun2
FatherFun3
SonFun1
SonFun2
SonFun3
请按任意键继续. . .
实际上和第六点结果是一样的。
8.如果父类有虚函数,子类没有定义虚函数,子类也会有虚函数表
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#ifdef _WIN64
#define PTR_VAL int64_t
#else
#define PTR_VAL int32_t
#endif
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 << "虚函数表地址: " << (PTR_VAL*)*(PTR_VAL*)&father << endl;
cout << "虚函数FatherFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&father << endl;
cout << "虚函数FatherFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&father + 1 << endl;
cout << "虚函数FatherFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&father + 2 << endl;
Fun fun = (Fun) * (PTR_VAL*)*(PTR_VAL*)&father;
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&father) + 1);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&father) + 2);
fun();
cout << "----------------测试子类------------------" << endl;
Son son;
cout << "类对象地址:" << &son << endl;
cout << "虚函数表地址: " << (PTR_VAL*)*(PTR_VAL*)&son << endl;
cout << "虚函数继承FatherFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&son << endl;
cout << "虚函数继承FatherFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 1 << endl;
cout << "虚函数继承FatherFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 2 << endl;
//cout << "虚函数sonFun1地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 3 << endl;
//cout << "虚函数sonFun2地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 4 << endl;
//cout << "虚函数sonFun3地址:" << (PTR_VAL*)*(PTR_VAL*)&son + 5 << endl;
fun = (Fun) * (PTR_VAL*)*(PTR_VAL*)&son;
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 1);
fun();
fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 2);
fun();
//fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 3);
//fun();
//fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 4);
//fun();
//fun = (Fun) * ((PTR_VAL*)*(PTR_VAL*)(&son) + 5);
//fun();
system("pause");
}
将子类中的虚函数注释掉,输出结果:
类对象地址:00000097B6CFF958
虚函数表地址: 00007FF6E459BCF8
虚函数FatherFun1地址:00007FF6E459BCF8
虚函数FatherFun2地址:00007FF6E459BD00
虚函数FatherFun3地址:00007FF6E459BD08
FatherFun1
FatherFun2
FatherFun3
----------------测试子类------------------
类对象地址:00000097B6CFF998
虚函数表地址: 00007FF6E459BD50
虚函数继承FatherFun1地址:00007FF6E459BD50
虚函数继承FatherFun2地址:00007FF6E459BD58
虚函数继承FatherFun3地址:00007FF6E459BD60
FatherFun1
FatherFun2
FatherFun3
请按任意键继续. . .
第6条确认。