仮想関数テーブルポインターを使用して仮想関数を呼び出すときに発生する問題

仮想関数テーブルポインターを使用して仮想関数を呼び出すときに発生する問題

父クラスを定義すると、コードは次のようになります。

クラスFather {
public:
virtual void func1(){cout << "Father :: func1" << endl;}
virtual void func2(){cout << "Father :: func2" << endl; }
virtual void func3(){cout << "Father :: func3" << endl; }
void func4(){cout << "非虚函数:Father :: func4" << endl; }
public:
int x = 200;
int y = 300;
静的整数z;
};

typedef void(* func_t)(void);

int main(void){

Father father;


cout << "对象father地址:" <<(int)&father << endl;
int* vptr = (int*)*(int*)(&father);//函数指针,int*类型
cout << "vptr:" << vptr << endl;

//((void (*)(void))vptr)(); wrong

((void(*)(void))*(vptr))();

((func_t) * (vptr + 0))();
((func_t) * (vptr + 1))();
((func_t) * (vptr + 2))();

0を返します。

}

説明:父親オブジェクトのアドレスを取得してアドレスを取得します。アドレスに格納されている値は仮想関数テーブルポインターであり、関数ポインターは4バイトを占有するため、アドレスは(int *)型に変換され、コンパイラーのメモリーサイズを通知します。次に、仮想関数テーブルポインターを取得するために逆参照し、最後に(int *)型に変換し、仮想関数テーブルポインターを取得します。今回は(int *)型であり、最後にこのint *型ポインターを通じて仮想関数を呼び出します電話?ポインターが指す仮想関数の戻り値は空であるため、最初にポインターの型を変更します。

タイプを定義します

typedef void(* func_t)(void);

次に、コードを記述します((func_t)*(vptr + 0))();仮想関数を呼び出すことができます。つまり、最初に仮想関数テーブルのポインターを逆参照して、仮想関数のポインターを取得します。ここで注意:仮想関数テーブルのポインターと仮想関数のポインターを区別してくださいポインタ!そうしないと、エラーが発生し、ここで2回逆参照する必要があります。1つ目は、仮想関数テーブルポインターを取得するために&親を逆参照し、次に仮想関数ポインターを取得するために仮想関数テーブルポインターを逆参照することです。

したがって、カスタム型なしで仮想関数を呼び出すことは非常に明確です。コードは次のように記述する必要があります
:((void(*)(void)))*(vptr))();
((void (*)(void)))(vptr))();仮想関数テーブルのポインターを仮想関数のポインターと混同するのは冗談です。

主に仮想関数テーブルポインタの概念を理解!

おすすめ

転載: www.cnblogs.com/Ybossy/p/12737069.html