1.通过对象调用成员函数(无虚函数)
- 源代码
class Base {
public:
void Function_1() {
printf("func1...\n");
}
void Function_2() {
printf("func2...\n");
}
};
int main()
{
Base base;
base.Function_1();
base.Function_2();
}
- 反汇编代码
Base base;
base.Function_1();
00D419E2 8D 4D F7 lea ecx,[base]
00D419E5 E8 45 F9 FF FF call Base::Function_1 (0D4132Fh)
base.Function_2();
00D419EA 8D 4D F7 lea ecx,[base] ;ecx = this指针,对象首地址
00D419ED E8 5C F8 FF FF call Base::Function_2 (0D4124Eh) ; E8 call 直接调用
2. 通过对象调用成员函数(有虚函数)
class Base {
public:
void Function_1() {
printf("func1...\n");
}
virtual void Function_2() {
printf("func2...\n");
}
};
int main()
{
Base base;
base.Function_1();
base.Function_2();
}
Base base;
009C1A82 8D 4D F4 lea ecx,[base]
009C1A85 E8 C4 F7 FF FF call Base::Base (09C124Eh)
base.Function_1();
009C1A8A 8D 4D F4 lea ecx,[base] ;
009C1A8D E8 C0 F8 FF FF call Base::Function_1 (09C1352h)
base.Function_2();
009C1A92 8D 4D F4 lea ecx,[base] ;;
009C1A95 E8 3D F6 FF FF call Base::Function_2 (09C10D7h) ;
- 对比发现通过对象调用普通函数与虚函数的汇编代码没有区别,都是E8 call(直接调用)
3. 通过对象指针调用成员函数(有虚函数)
类中有虚函数时(无继承),类的大小会增加4字节,存放的是一个指向虚表的指针,虚表指针存放在对象首地址
class Base {
public:
void Function_1() {
printf("func1...\n");
}
virtual void Function_2() {
printf("func2...\n");
}
};
int main()
{
Base base;
Base* pb = &base;
pb->Function_1();
pb->Function_2();
}
Base base;
00BF1A82 8D 4D F4 lea ecx,[base]
00BF1A85 E8 C4 F7 FF FF call Base::Base (0BF124Eh)
Base* pb = &base;
00BF1A8A 8D 45 F4 lea eax,[base]
Base* pb = &base;
00BF1A8D 89 45 E8 mov dword ptr [pb],eax
pb->Function_1();
00BF1A90 8B 4D E8 mov ecx,dword ptr [pb]
00BF1A93 E8 BA F8 FF FF call Base::Function_1 (0BF1352h) ;普通函数还是直接调用
pb->Function_2();
00BF1A98 8B 45 E8 mov eax,dword ptr [pb]
00BF1A9B 8B 10 mov edx,dword ptr [eax]
00BF1A9D 8B F4 mov esi,esp
00BF1A9F 8B 4D E8 mov ecx,dword ptr [pb]
00BF1AA2 8B 02 mov eax,dword ptr [edx] ;
00BF1AA4 FF D0 call eax ; FF call 是间接调用,eax存的是某个虚函数地址
4. 通过虚表指针调用虚函数
class Base {
public:
Base() {
int x = 1;
int y = 1;
}
int x;
int y;
void Function_1() {
printf("func1...\n");
}
virtual void Function_2() {
printf("func2...\n");
}
virtual void Function_3() {
printf("func3...\n");
}
virtual void Function_4() {
printf("func4...\n");
}
virtual void Function_5() {
printf("func5...\n");
}
};
//定义一个函数指针类型
typedef void(*pFunction)(void);
int main()
{
pFunction pFn;
Base base;
Base* pb = &base;
//对象的前四个字节为虚表指针
//printf("base的虚表地址为:%d\n",*(int*)&base);
//通过虚表指针调用虚函数
for (int i = 0; i < 4; i++) {
int tmp = *((int*)(*(int*)&base) + i);
pFn = (pFunction)tmp;
pFn();
}
/*pb->Function_1();
pb->Function_2(); */
}
5 有继承关系打印虚表
5.1 单继承无函数重写
struct Base {
public:
Base() {
int x = 1;
int y = 1;
}
int x;
int y;
virtual void Function_1() {
printf("base:func1...\n");
}
virtual void Function_2() {
printf("base:func2...\n");
}
virtual void Function_3() {
printf("base:func3...\n");
}
};
struct Sub :Base {
virtual void Function_4() {
printf("Sub:func4...\n");
}
virtual void Function_5() {
printf("Sub:func5...\n");
}
virtual void Function_6() {
printf("Sub:func6...\n");
}
};
//定义一个函数指针
typedef void(*pFunction)(void);
int main()
{
pFunction pFn;
Sub sub;
Base* pb = ⊂//父类指针指向子类对象
//对象的前四个字节为虚表指针
//printf("base的虚表地址为:%d\n",*(int*)&base);
//通过虚表指针调用虚函数
for (int i = 0; i < 6; i++) {
int tmp = *((int*)(*(int*)&sub) + i);
pFn = (pFunction)tmp;
pFn();
}
/*pb->Function_1();
pb->Function_2(); */
}
- 运行结果:
base:func1...
base:func2...
base:func3...
Sub:func4...
Sub:func5...
Sub:func6...
5.2 单继承有函数重写
struct Base {
public:
Base() {
int x = 1;
int y = 1;
}
int x;
int y;
virtual void Function_1() {
printf("base:func1...\n");
}
virtual void Function_2() {
printf("base:func2...\n");
}
virtual void Function_3() {
printf("base:func3...\n");
}
};
struct Sub :Base {
virtual void Function_1() {
printf("Sub:func1...\n");
}
virtual void Function_2() {
printf("Sub:func2...\n");
}
virtual void Function_6() {
printf("Sub:func6...\n");
}
};
//定义一个函数指针
typedef void(*pFunction)(void);
int main()
{
pFunction pFn;
Sub sub;
Base* pb = ⊂//父类指针指向子类对象
//对象的前四个字节为虚表指针
//printf("base的虚表地址为:%d\n",*(int*)&base);
//通过虚表指针调用虚函数
for (int i = 0; i < 4; i++) {
int tmp = *((int*)(*(int*)&sub) + i);
pFn = (pFunction)tmp;
pFn();
}
/*pb->Function_1();
pb->Function_2(); */
}
- 运行结果: 子类覆盖父类中同名的
Sub:func1...
Sub:func2...
base:func3...
Sub:func6...
5.3 多继承无函数重写
多继承,假如有两个直接父类,会有两张虚表,对象的前八个字节为两个虚表指针
#include <iostream>
#include <stdio.h>
using namespace std;
struct Base1 {
virtual void Function_1() {
printf("base1:func1...\n");
}
virtual void Function_2() {
printf("base1:func2...\n");
}
virtual void Function_3() {
printf("base1:func3...\n");
}
};
struct Base2 {
virtual void Function_4() {
printf("base2:func4...\n");
}
virtual void Function_5() {
printf("base2:func5...\n");
}
virtual void Function_6() {
printf("base2:func6...\n");
}
};
struct Sub :Base1,Base2 {
int x = 5;
int y = 6;
virtual void Function_7() {
printf("Sub:func7...\n");
}
virtual void Function_8() {
printf("Sub:func8...\n");
}
virtual void Function_9() {
printf("Sub:func9...\n");
}
};
//定义一个函数指针
typedef void(*pFunction)(void);
int main()
{
pFunction pFn;
Sub sub;
//Base* pb = ⊂//父类指针指向子类对象
//对象的前四个字节为虚表指针
//通过虚表指针调用虚函数
//打印第一张虚表
printf("打印第一张虚表\n");
printf("第一张虚表地址为:%ld\n", *(int*)&sub);
for (int i = 0; i < 6; i++) {
int tmp = *((int*)(*(int*)&sub) + i);
pFn = (pFunction)tmp;
pFn();
}
printf("打印第二张虚表\n");
printf("第二张虚表地址为:%ld\n", *(int*)((int)&sub+4));
//打印第二张虚表
pFunction pFn2;
for (int i = 0; i < 3; i++) {
int tmp = *((int*)(*(int*)((int)&sub + 4)) + i);
pFn2 = (pFunction)tmp;
pFn2();
}
}
- 运行结果
打印第一张虚表
第一张虚表地址为:1690464
base1:func1...
base1:func2...
base1:func3...
Sub:func7...
Sub:func8...
Sub:func9...
打印第二张虚表
第二张虚表地址为:1691084
base2:func4...
base2:func5...
base2:func6...
5.4 多继承有函数重写
#include <iostream>
#include <stdio.h>
using namespace std;
struct Base1 {
virtual void Function_1() {
printf("base1:func1...\n");
}
virtual void Function_2() {
printf("base1:func2...\n");
}
virtual void Function_3() {
printf("base1:func3...\n");
}
};
struct Base2 {
virtual void Function_4() {
printf("base2:func4...\n");
}
virtual void Function_5() {
printf("base2:func5...\n");
}
virtual void Function_6() {
printf("base2:func6...\n");
}
};
struct Sub :Base1,Base2 {
int x = 5;
int y = 6;
virtual void Function_1() {
printf("Sub:func1...\n");
}
virtual void Function_4() {
printf("Sub:func4...\n");
}
virtual void Function_7() {
printf("Sub:func7...\n");
}
};
//定义一个函数指针
typedef void(*pFunction)(void);
int main()
{
pFunction pFn;
Sub sub;
//Base* pb = ⊂//父类指针指向子类对象
//对象的前四个字节为虚表指针
//通过虚表指针调用虚函数
//打印第一张虚表
printf("打印第一张虚表\n");
printf("第一张虚表地址为:%ld\n", *(int*)&sub);
for (int i = 0; i < 4; i++) {
int tmp = *((int*)(*(int*)&sub) + i);
pFn = (pFunction)tmp;
pFn();
}
printf("打印第二张虚表\n");
printf("第二张虚表地址为:%ld\n", *(int*)((int)&sub+4));
//打印第二张虚表
pFunction pFn2;
for (int i = 0; i < 3; i++) {
int tmp = *((int*)(*(int*)((int)&sub + 4)) + i);
pFn2 = (pFunction)tmp;
pFn2();
}
}
- 运行结果
重写的是哪个就在哪个表里
打印第一张虚表
第一张虚表地址为:13028192
Sub:func1...
base1:func2...
base1:func3...
Sub:func7...
打印第二张虚表
第二张虚表地址为:13028812
Sub:func4...
base2:func5...
base2:func6...
5.5 多层继承无函数重写
多层继承只有一个虚表
#include <iostream>
#include <stdio.h>
using namespace std;
struct Base1 {
virtual void Function_1() {
printf("base1:func1...\n");
}
virtual void Function_2() {
printf("base1:func2...\n");
}
};
struct Base2:Base1 {
virtual void Function_3() {
printf("base2:func4...\n");
}
virtual void Function_4() {
printf("base2:func5...\n");
}
};
struct Sub :Base2 {
virtual void Function_5() {
printf("Sub:func5...\n");
}
virtual void Function_6() {
printf("Sub:func6...\n");
}
};
//定义一个函数指针
typedef void(*pFunction)(void);
int main()
{
pFunction pFn;
Sub sub;
//Base* pb = ⊂//父类指针指向子类对象
//对象的前四个字节为虚表指针
//通过虚表指针调用虚函数
//打印第一张虚表
printf("打印第一张虚表\n");
printf("第一张虚表地址为:%ld\n", *(int*)&sub);
for (int i = 0; i < 6; i++) {
int tmp = *((int*)(*(int*)&sub) + i);
pFn = (pFunction)tmp;
pFn();
}
//printf("打印第二张虚表\n");
//printf("第二张虚表地址为:%ld\n", *(int*)((int)&sub+4));
////打印第二张虚表
//pFunction pFn2;
//for (int i = 0; i < 3; i++) {
// int tmp = *((int*)(*(int*)((int)&sub + 4)) + i);
// pFn2 = (pFunction)tmp;
// pFn2();
//}
}
- 运行结果:
打印第一张虚表
第一张虚表地址为:4967372
base1:func1...
base1:func2...
base2:func4...
base2:func5...
Sub:func5...
Sub:func6...
5.5 多层继承有函数重写
#include <iostream>
#include <stdio.h>
using namespace std;
struct Base1 {
virtual void Function_1() {
printf("base1:func1...\n");
}
virtual void Function_2() {
printf("base1:func2...\n");
}
};
struct Base2:Base1 {
virtual void Function_3() {
printf("base2:func3...\n");
}
virtual void Function_4() {
printf("base2:func4...\n");
}
};
struct Sub :Base2 {
virtual void Function_1() {
printf("Sub:func1...\n");
}
virtual void Function_3() {
printf("Sub:func3...\n");
}
};
//定义一个函数指针
typedef void(*pFunction)(void);
int main()
{
pFunction pFn;
Sub sub;
//Base* pb = ⊂//父类指针指向子类对象
//对象的前四个字节为虚表指针
//通过虚表指针调用虚函数
//打印第一张虚表
printf("打印第一张虚表\n");
printf("第一张虚表地址为:%ld\n", *(int*)&sub);
for (int i = 0; i < 4; i++) {
int tmp = *((int*)(*(int*)&sub) + i);
pFn = (pFunction)tmp;
pFn();
}
//printf("打印第二张虚表\n");
//printf("第二张虚表地址为:%ld\n", *(int*)((int)&sub+4));
////打印第二张虚表
//pFunction pFn2;
//for (int i = 0; i < 3; i++) {
// int tmp = *((int*)(*(int*)((int)&sub + 4)) + i);
// pFn2 = (pFunction)tmp;
// pFn2();
//}
}
- 运行结果:
打印第一张虚表
第一张虚表地址为:6015948
Sub:func1...
base1:func2...
Sub:func3...
base2:func4...
网友评论