• 如何通过函数名获取虚函数的地址?


    测试环境:WIN8+VS2012

    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    class Cbase{
    public:
    	Cbase() : x(10){}
    	virtual void f(){cout << "Cbase::f" << endl;}
    	virtual void g(){cout << "Cbase::g" << endl;}
    	virtual void h(){cout << "Cbase::h" << endl;}
    private:
    	int x;
    };
    typedef void(*FUN)();
    typedef void(Cbase::*PFUN)();
    int main(void)
    {
    	Cbase a;
    	printf("f = 0%X
    ", &Cbase::f);
    	printf("g = 0%X
    ", &Cbase::g);
    	printf("h = 0%X
    ", &Cbase::h);
    
    	PFUN c1 = &Cbase::f;
    	PFUN c2 = &Cbase::g;
    	PFUN c3 = &Cbase::h;
    	(a.*c1)();
    	(a.*c2)();
    	(a.*c3)();
    
    	return 0;
    }
    输出:


    既然能够正常输出,我们有理由相信&Cbase::f,&Cbase::g,&Cbase::h,是虚函数表里的地址,事实是这样吗?


    有些书上说是获取到虚函数在虚函数表中的索引。但是实际上VS编译器并不是这么做的,获取到的将会是一个用于虚函数调用的地址,这个地址上的指令会先获取虚函数表,然后再通过虚函数表获取虚函数地址相关的项。而GCC的做法又跟VS不同,通过&获取得的值都是1。总而言之,通过取地址&符号获得的不是函数地址,但是可以通过获得的值成功调用该函数。

    但在vs中,成员函数指针不是指向函数的真实地址,而是先指向一个位置,该位置会调用Cbase::`vcall'{0}':之后才跳转到真正地址。不同的函数,Cbase::`vcall'{0}':中的数字不同。


    本质上还是编译时确定好每个函数的位置,通过此位置来查询虚函数表。


    而在VS中,*(int*)*(int*)(&b)也依旧取不到虚函数表地址


    可见经过了一次jmp

    为什么会jmp,其实和普通函数一样

    http://blog.csdn.net/x_iya/article/details/13161937




    ====================

    #include <map>
    #include <iostream>
    using namespace std;
    
    class Base
    {
    public:
    	virtual void Iam()
    	{
    		cout<<"Base::Iam"<<endl;
    	}
    	virtual void FunBase()
    	{
    		cout<<"Base::FunBase"<<endl;
    	}
    };
    
    
    class BaseSec
    {
    public:
    	virtual void Iam()
    	{
    		cout<<"BaseSec::Iam"<<endl;
    	}
    	virtual void FunSec()
    	{
    		cout<<"BaseSec::FunSec"<<endl;
    	}
    };
    
    class Child: public Base, public BaseSec
    {
    public:
    	virtual void Iam()
    	{
    		cout<<"Child::Iam"<<endl;
    	}
    
    	virtual void Fun()
    	{
    		cout<<"Child::Fun"<<endl;
    	}
    };
    
    int main(void)
    {
    	typedef void(*Fun)(void);
    	Fun fun;
    	Child child;
    	typedef void (*Fun)(void);
    	int **p = (int**)&child;
    	cout << p[0][0] << endl;
    	fun = (Fun)p[0][0];
    	fun();
    
    	cout << p[0][1] << endl;
    	fun = (Fun)p[0][1];
    	fun();
    
    	cout << p[0][2] << endl;
    	fun = (Fun)p[0][2];
    	fun();
    
    	p = (int**)&child+1;
    
    	cout << p[0][0] << endl;
    	fun = (Fun)p[0][0];
    	fun();
    
    	cout << p[0][1] << endl;
    	fun = (Fun)p[0][1];
    	fun();
    	return 0;
    }


    Keep it simple!
    作者:N3verL4nd
    知识共享,欢迎转载。
  • 相关阅读:
    fastjson反序列化漏洞研究(上)
    csv注入复现代码
    day24-python之面向对象
    day23-python之日志 re模块
    day22-python之模块
    day21-python模块
    day20-python之装饰器
    day18-python之迭代器和生成器
    day17-python之文件操作
    day16-python之函数式编程匿名函数
  • 原文地址:https://www.cnblogs.com/lgh1992314/p/5834839.html
Copyright © 2020-2023  润新知