使用函数指针调用C++虚函数

时间:2021-07-12 21:58:26

基本概念:

  1. 函数指针,一个地址指针变量,其值指向代码区的某个函数首地址。

  2. 虚函数,可以被子类覆写的C++成员函数。由虚函数表实现。

  3. 虚函数表指针(vpt),指向虚函数表首地址的指针,一般放在类实例的首4字节(x86系统)。通过它能找的虚函数表,进而能找的某个虚函数。

函数调用:

  1. C++函数的普通调用方式:      

class Person {
private:
int value;
public:
Person():value(){}
virtual int getValue(int a) {
return value + a;
}
}; void main() {
Person p;
int result = p.getValue(); // result 为 130
}

  2. 使用普通函数指针调用:

class Person {
private:
int value;
public:
Person():value(){}
virtual int getValue(int a) {
return value + a;
}
}; typedef int (Person::PFUNC) (int);    // 定义函数指针类型 void main() {
PFUNC pf = &Person::getValue;      // 定义变量
Person p;
// int result = p.getValue(30);
int result = p.*pf(); // result 为 130
result = &p->*pf();   // 语法与上句一样
}

  3. 使用函数指针外部调用

class Person {
private:
int value;
public:
Person():value(){}
virtual int getValue(int a) {
return value + a;
}
}; typedef int (PFUNC) (int);    // 定义函数指针类型 void main() {
Person p, *pp;
pp = &p;
PFUNC pf = (PFUNC)**(int **)pp; // 通过虚函数表获得虚函数pf
int result = pf(); // 崩了,因为没有this指针
} /*以下是老师提供的代码,但是也崩了*/
void main() {
Person p, *pp;
pp = &p;
PFUNC pf = (PFUNC)**(int **)pp; // 通过虚函数表获得虚函数pf
__asm mov ecx, pp           // 传入this指针
int result = pf(); // 还是崩了
}

 

对于第三种方式,this指针传不进去,然后一直报错:

  The value of ESP was not properly saved across a function call.  This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

  如果我把getValue函数换成无参的,两种方法都可以调用。但是结果第一种是随机数,第二种是100。可见第二种通过汇编方式确实传进去了this指针,(在有多继承时这个this指针一般会做调整的),第一种随机数的原因是它的this指针是类模板装载入内存时的模板首地址,显然它没有初始化。

  回到上题,我还在纠结于怎么传参!