【C/C++】【对象模型】虚函数

时间:2020-07-23 22:31:57   收藏:0   阅读:70

虚函数表指针位置分析

类:有虚函数,会产生一个虚函数表;

类对象:有一个指针,指针vptr会指向虚函数表的开始地址;

虚函数指针的位置

虚函数表位于整个对象模型的顶端;

// objModel.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
using namespace std;
class A
{
public:
    virtual void func() {};

public:
    int i;
};

int main()
{
    A a;
    cout << sizeof(a) << endl;

    char* p = reinterpret_cast<char*>(&a);
    char* q = reinterpret_cast<char*>(&a.i);

    if (p == q) //如果二者位置相同,说明i在对象的上面;虚函数表指针vptr在下面;
        cout << "yes" << endl;
    else
        cout << "no" << endl; 
    return 0;
}

继承关系作用下虚函数的手工调用

技术图片

// objModel.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
using namespace std;
class Base
{
public:
    virtual void func()
    {
        cout << "Base::void func()" << endl;
    }

    virtual void gunc()
    {
        cout << "Base::void gunc()" << endl;
    }


    virtual void hunc()
    {
        cout << "Base::void hunc()" << endl;
    }
};


class Derive :public Base
{
public:
    virtual void gunc()
    {
        cout << "Derive::void hunc()" << endl;
    }
};

int main()
{
    //直接用类名和用对象一样,都是这个类的对象的大小
    cout << sizeof(Base) << endl; //父类 4字节
    cout << sizeof(Derive) << endl; //子类 4字节
    
    
    Derive* d = new Derive(); //派生类指针
    long* pvptr = (long*)d; //指向对象的指针d转成了long*类型
    long* vptr = (long*)(*pvptr); //(*pvptr)表示pvptr所指向的对象,也就是Derive本身, Derive对象是4字节,代表的是虚函数表指针



    for (int i = 0; i <= 2; i++) //循环3次 打印虚函数的入口地址
    {
        printf("vptr[%d] = 0x:%p\n", i, vptr[i]);
    }
    
    typedef void(*Func)(void); //定义一个函数指针类型
    Func f = (Func)vptr[0]; //f是函数指针变量,vptr[0]是指向第一个虚函数;
    Func g = (Func)vptr[1]; //f是函数指针变量,vptr[1]是指向第二个虚函数;
    Func h = (Func)vptr[2]; //f是函数指针变量,vptr[2]是指向第三个虚函数;
    
    f();
    g();
    h();


    cout << "---------------------------------------------------------------------" << endl;


    Base* b = new Base(); //基类指针
    long* pvptr_base = (long*)b; //指向对象的指针b转成了long*类型
    long* vptr_base = (long*)(*pvptr_base);

    for (int i = 0; i <= 2; i++) //循环3次 打印虚函数的入口地址
    {
        printf("Base[%d] = 0x:%p\n", i, vptr_base[i]);
    }
    Func f_base = (Func)vptr_base[0]; //f_base是函数指针变量,vptr_base[0]是指向第一个虚函数;
    Func g_base = (Func)vptr_base[1]; //g_base是函数指针变量,vptr_base[1]是指向第二个虚函数;
    Func h_base = (Func)vptr_base[2]; //h_base是函数指针变量,vptr_base[2]是指向第三个虚函数;
    f_base();
    g_base();
    h_base();

    return 0;
}

虚函数表分析

// objModel.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//基类不同对象虚函数指针
//基类和父类对象 虚函数指针

#include <iostream>
using namespace std;
class Base
{
public:
    virtual void func()
    {
        cout << "Base::void func()" << endl;
    }

    virtual void gunc()
    {
        cout << "Base::void gunc()" << endl;
    }


    virtual void hunc()
    {
        cout << "Base::void hunc()" << endl;
    }
};


class Derive :public Base
{
public:
    virtual void gunc()
    {
        cout << "Derive::void hunc()" << endl;
    }
};

int main()
{
    //直接用类名和用对象一样,都是这个类的对象的大小
    cout << sizeof(Base) << endl; //父类 4字节
    cout << sizeof(Derive) << endl; //子类 4字节
    
    
    Derive derive; //__vfptr = 0x00f89b90 {objModel.exe!void(* Derive::`vftable‘[4])()} {0x00f812da {objModel.exe!Base::func(void)}, ...}
    long* p_vptr_derive = (long*)(&derive); //指向对象的指针d转成了long*类型
    long* vptr_derive = (long*)(*p_vptr_derive); //(*pvptr)表示pvptr所指向的对象,也就是Derive本身, Derive对象是4字节,代表的是虚函数表指针

    typedef void(*Func)(void); //定义一个函数指针类型
    Func f = (Func)vptr_derive[0]; //f是函数指针变量,vptr_derive[0]是指向第一个虚函数;
    Func g = (Func)vptr_derive[1]; //f是函数指针变量,vptr_derive[1]是指向第二个虚函数;
    Func h = (Func)vptr_derive[2]; //f是函数指针变量,vptr_derive[2]是指向第三个虚函数;



    Derive derive_2 = derive; //调用拷贝构造函数  __vfptr = 0x00f89b90 {objModel.exe!void(* Derive::`vftable‘[4])()} {0x00f812da {objModel.exe!Base::func(void)}, ...}
    long* p_vptr_derive_2 = (long*)(&derive_2); //指向对象的指针d转成了long*类型
    long* vptr_derive_2 = (long*)(*p_vptr_derive_2); //(*pvptr)表示pvptr所指向的对象,也就是Derive本身, Derive对象是4字节,代表的是虚函数表指针


    Func f_2 = (Func)vptr_derive_2[0]; //f是函数指针变量,vptr_derive[0]是指向第一个虚函数;
    Func g_2 = (Func)vptr_derive_2[1]; //f是函数指针变量,vptr_derive[1]是指向第二个虚函数;
    Func h_2 = (Func)vptr_derive_2[2]; //f是函数指针变量,vptr_derive[2]是指向第三个虚函数;



    //直接用子类对象给父类对象值,子类中属于分类的那部分内容会被编译器自动区分出来,并拷贝给了父类对象
    //所以Base base = derive; 实际上做了两件事
    //1. 生成一个base对象
    //2. 用derive来初始化base对象的值,编译器做了选择,derive的虚函数表指针值并没有覆盖base对象的虚函数表指针值;
    Base base = derive; //直接用子类对象给父类对象值 __vfptr = 0x00f89b34 {objModel.exe!void(* Base::`vftable‘[4])()} {0x00f812da {objModel.exe!Base::func(void)}, ...}
    long* p_vptr_base = (long*)(&base); //指向对象的指针d转成了long*类型
    long* vptr_base = (long*)(*p_vptr_base); //(*

    Func f_base = (Func)vptr_base[0]; //f是函数指针变量,vptr_derive[0]是指向第一个虚函数;
    Func g_base = (Func)vptr_base[1]; //f是函数指针变量,vptr_derive[1]是指向第二个虚函数;
    Func h_base = (Func)vptr_base[2]; //f是函数指针变量,vptr_derive[2]是指向第三个虚函数;


    //面向对象oo和基于对象ob
    // 1. C++通过类的指针和引用来支持多态,就是面向对象OO;
    // 2. OB,也叫ADT抽象数据模型,不支持多态,执行速度更快,因为函数调用的解析不需要运行时决定(没有多态)
    //    因为函数调用的解析不需要运行时决定(没有多态),而是在编译器期间就解析完成,内存空间紧凑程度上更紧凑,因为没有虚函数指针和虚函数表这些概念;
    //    但是OB的设计灵活性就差;

    //C++既支持OO,有支持OB;

    return 0;
}

多重继承虚函数表分析

技术图片


#include <iostream>
using namespace std;



class Base_1
{
public:
	virtual void func()
	{
		cout << "Base_1::void func()" << endl;
	}

	virtual void gunc()
	{
		cout << "Base_1::void gunc()" << endl;
	}
};



class Base_2
{
public:
	virtual void hunc()
	{
		cout << "Base_2::void func()" << endl;
	}

	virtual void iunc()
	{
		cout << "Base_2::void gunc()" << endl;
	}
};




class Derived :public Base_1, public Base_2
{
public:
	virtual void func()
	{
		cout << "Derived::void func()" << endl;
	}
	virtual void iunc()
	{
		cout << "Derived::void iunc()" << endl;
	}



	//自己的虚函数
	virtual void munc()
	{
		cout << "Derived::void munc()" << endl;
	}
	virtual void nunc()
	{
		cout << "Derived::void nunc()" << endl;
	}
	virtual void junc()
	{
		cout << "Derived::void junc()" << endl;
	}
};

int main()
{
	//多重继承虚函数表分析
	cout << sizeof(Base_1) << endl;
	cout << sizeof(Base_2) << endl;
	cout << sizeof(Derived) << endl;

	Derived derive;
	Base_1& b_1 = derive;
	Base_2& b_2 = derive;
	Derived& d = derive;


	typedef void(*Func)(void);

	long* p_derived_1 = (long*)(&derive);
	long* vptr_1 = (long*)(*p_derived_1); //取第一个虚函数表指针



	long* p_derived_2 = p_derived_1 + 1; 
	long* vptr_2 = (long*)(*p_derived_2); //取第二个虚函数表指针



	Func f_1_1 = (Func)vptr_1[0]; //f_1_1 = 0x0039146f {objModel.exe!Derived::func(void)}
	Func f_1_2 = (Func)vptr_1[1]; //f_1_2 = 0x00141460 {objModel.exe!Base_1::gunc(void)}
	Func f_1_3 = (Func)vptr_1[2]; //f_1_3 = 0x00141483 {objModel.exe!Derived::munc(void)}
	Func f_1_4 = (Func)vptr_1[3]; //f_1_4 = 0x00141492 {objModel.exe!Derived::nunc(void)}
	Func f_1_5 = (Func)vptr_1[4]; //f_1_5 = 0x0014146a {objModel.exe!Derived::junc(void)}

	Func f_2_1 = (Func)vptr_2[0]; //f_2_1 = 0x00141479 {objModel.exe!Base_2::hunc(void)}
	Func f_2_2 = (Func)vptr_2[1]; //f_2_2 = 0x0014145b {objModel.exe!Derived::iunc(void)}

	f_1_1();
	f_1_2();
	f_1_3();
	f_1_4();
	f_1_5();

	cout << "-----------------------------" << endl;

	f_2_1();
	f_2_2();


	//

	return 0;
}

vptr/vtbl创建时机

辅助工具: **cl.exe ** 编译链接工具

虚函数调用问题

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!