1.引言
本文介绍以下4个部分:
(1)虚函数
(2)虚函数表
(3)直接调用private修饰的虚函数、传递任意this指针给调用的函
(4)多态、this、虚函数表
2.虚函数
定义:简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异,而采用不同的策略。
3.虚函数表
虚函数表首地址存在于class对象的起始位置。虚函数可以被继承,子类重写的虚函数会覆盖虚函数表中父类的虚函数的地址。
通过this来查对应的虚函数表来实现多态。
4.接调用private修饰的虚函数
4.1无this指针
通过函数指针指向虚函数表中需要调用的虚函数地址,作为普通函数进行调用。
4.2修复this指针
(1)在调用成员函数的时候,编译器隐式地传递了this指针这个参数,this不是通过栈进行的传递,而是通过ecx寄存器传值。
(2)修复this指针,在函数中读取class A的成员变量a
(3)传递任意class的this给调用的虚函数
调用A的AF函数,传递B的this,实现AF函数中读取出B的成员变量。
需要注意的是,在传递B的this指针时,要算好this+offset
5.多态
静态多态:子类重写父类的相同函数
动态多态:父类指针指向子类对象,调用子类虚函数方法
6.总结
(1)多态实现的灵魂就是this指针,this指针指向了虚函数表的首地址。this指针决定了调用虚函数时查哪个类的虚函数表。
(2)调用虚函数是间接call,调用普通函数是直接call。
(3)虚函数表首地址位于class的起始地址,这样是为了继承时查表方便。
(4)a = B(); a.AF();不是多态,因为,this传递的是a的,并且是直接call
#include "stdio.h"
class
A
{
private
:
virtual
void
AF() {
printf
(
"AF run...\n"
);
}
};
int
main()
{
A a;
typedef
void
(*Myfunction)();
Myfunction f = (Myfunction)(*(
int
*)(*(
int
*)(&a)));
f();
}
运行结果:AF run...
#include "stdio.h"
class
A
{
private
:
virtual
void
AF() {
printf
(
"AF run...\n"
);
}
};
int
main()
{
A a;
typedef
void
(*Myfunction)();
Myfunction f = (Myfunction)(*(
int
*)(*(
int
*)(&a)));
f();
}
运行结果:AF run...
#include "stdio.h"
class
A
{
public
:
int
a = 1;
private
:
virtual
void
AF() {
printf
(
"AF run...\n"
);
printf
(
"a=%d\n"
,
this
->a);
}
public
:
virtual
void
test(
int
a) {
printf
(
"test run...%x\n"
, a);
}
};
int
main()
{
A a;
a.test(0x12345678);
}
运行结果:test run...12345678
——————————————————————————————汇编代码————————————————————————————————
A a;
00B51B4F 8D 4D F0 lea ecx,[a]
00B51B52 E8 AA F8 FF FF call A::A (0B51401h)
a.test(0x12345678);
00B51B57 68 78 56 34 12 push 12345678h
00B51B5C 8D 4D F0 lea ecx,[a]
00B51B5F E8 01 F9 FF FF call A::test (0B51465h)
#include "stdio.h"
class
A
{
public
:
int
a = 1;
private
:
virtual
void
AF() {
printf
(
"AF run...\n"
);
printf
(
"a=%d\n"
,
this
->a);
}
public
:
virtual
void
test(
int
a) {
printf
(
"test run...%x\n"
, a);
}
};
int
main()
{
A a;
a.test(0x12345678);
}
运行结果:test run...12345678
——————————————————————————————汇编代码————————————————————————————————
A a;
00B51B4F 8D 4D F0 lea ecx,[a]
00B51B52 E8 AA F8 FF FF call A::A (0B51401h)
a.test(0x12345678);
00B51B57 68 78 56 34 12 push 12345678h
00B51B5C 8D 4D F0 lea ecx,[a]
00B51B5F E8 01 F9 FF FF call A::test (0B51465h)
#include "stdio.h"
class
A
{
public
:
int
a = 1;
private
:
virtual
void
AF() {
printf
(
"AF run...\n"
);
printf
(
"a=%d\n"
,
this
->a);
}
};
int
main()
{
A a;
A* pA = &a;
typedef
void
(*Myfunction)();
Myfunction f = (Myfunction)(*(
int
*)(*(
int
*)(&a)));
__asm
{
mov ecx, pA;
}
f();
}
运行结果:
AF run...
a=1
#include "stdio.h"
class
A
{
public
:
int
a = 1;
private
:
virtual
void
AF() {
printf
(
"AF run...\n"
);
printf
(
"a=%d\n"
,
this
->a);
}
};
int
main()
{
A a;
A* pA = &a;
typedef
void
(*Myfunction)();
Myfunction f = (Myfunction)(*(
int
*)(*(
int
*)(&a)));
__asm
{
mov ecx, pA;
}
f();
}
运行结果:
AF run...
a=1
#include "stdio.h"
class
A
{
public
:
int
a = 1;
private
:
virtual
void
AF() {
printf
(
"AF run...\n"
);
printf
(
"a=%d\n"
,
this
->a);
}
};
class
B:
public
A
{
public
:
int
a = 2;
private
:
virtual
void
AF() {
printf
(
"BF run...\n"
);
printf
(
"a=%d\n"
,
this
->a);
}
};
int
main()
{
A a;
B b;
typedef
void
(*Myfunction)();
Myfunction f = (Myfunction)(*(
int
*)(*(
int
*)(&a)));
B* pA = &b;
__asm
{
mov ecx, pA;
add ecx, 4;
}
f();
}
运行结果:
AF run...
a=2
#include "stdio.h"
class
A
{
public
:
int
a = 1;
private
:
virtual
void
AF() {
printf
(
"AF run...\n"
);
printf
(
"a=%d\n"
,
this
->a);
}
};
class
B:
public
A
{
public
:
int
a = 2;
private
:
virtual
void
AF() {
printf
(
"BF run...\n"
);
printf
(
"a=%d\n"
,
this
->a);
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2023-9-3 22:24
被ATrueMan编辑
,原因: 格式