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

基本概念:

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

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

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

函数调用:

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

class Person {
private:
   int value;
public:
   Person():value(100){} 
   virtual int getValue(int a) {
       return value + a;         
   }  
};

void main() {
  Person p;
  int result = p.getValue(30);    // result 为 130
}

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

class Person {
private:
   int value;
public:
   Person():value(100){} 
   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(30);               // result 为 130
  result = &p->*pf(30);                // 语法与上句一样
}

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

class Person {
private:
   int value;
public:
   Person():value(100){} 
   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(30);               // 崩了,因为没有this指针
}

/*以下是老师提供的代码,但是也崩了*/
void main() {
  Person p, *pp;
  pp = &p;
  PFUNC pf = (PFUNC)**(int **)pp;    // 通过虚函数表获得虚函数pf
  __asm mov ecx, pp           // 传入this指针
  int result = pf(30);               // 还是崩了
}

 

对于第三种方式,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指针是类模板装载入内存时的模板首地址,显然它没有初始化。

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

posted @ 2014-08-05 14:22  南国生红豆  阅读(788)  评论(0编辑  收藏  举报