探究C++对象模型

先引用两句名言作为开场白:

"C++老手分两类:一种人把语言用得烂熟,OO观念也有;另一种人不但如此,还对于台面下的机制,如编译器合成的default constructor、object的内存布局等有莫大的兴趣。"

"了解C++对象模型,绝对有助于你在语言本身以及面向对象观念两方面的层次提升。"

首先以Point类为例

探究C++对象模型_第1张图片

再看下对象模型

探究C++对象模型_第2张图片

这个模型好像跟我们以往的认知有些不一致呀,vtable首四个字节怎么是type_info的指针?type_info是RTTI的内容,是编译器用来进行类型识别的,它到底存不存在呢?

用代码测试一下

// VirtualTable.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
using namespace std;

class Base {
	private:
		int x;
	
     public:
            virtual void f() { cout<<"Base::f"<<endl; };
            virtual void g() { cout<<"Base::g"<<endl; };
            virtual void h() { cout<<"Base::h"<<endl; };
			Base(){x = 2;};

 
};




class Derive : public Base{
	private:
	int y;
     public:
            virtual void f1() { cout<<"Derive::f1"<<endl; };
            virtual void g1() { cout<<"Derive::g1"<<endl; };
            virtual void h1() { cout<<"Derive::h1"<<endl; };
			Derive(){y = 3;};
 
};

int main(int argc, char* argv[])
{

	typedef void(*Fun)(void);
 
    Base b;
	Derive d;
 
    Fun pFun = NULL;
 
    cout <<"虚函数表入口指针地址"<< (int*)(&b) << endl;
    cout <<"虚函数表的地址"<< (int*)*(int*)(&b) << endl;

	cout <<"Base — 第一个数据成员"<< *((int*)(&b)+1) << endl;
	cout <<"Derive — 第一个数据成员"<< *((int*)(&d)+1) << endl;
	cout <<"Derive — 第二个数据成员"<< *((int*)(&d)+2) << endl;
 
    // Invoke the first virtual function 
    pFun = (Fun)*((int*)*(int*)(&b));
    
	pFun = (Fun)*((int*)*(int*)(&b)+0);  // Base::f()
	pFun();
    pFun = (Fun)*((int*)*(int*)(&b)+1);  // Base::g()
	pFun();
    pFun = (Fun)*((int*)*(int*)(&b)+2);  // Base::h()
	pFun();
	//以上代码说明 虚函数表位于对象内存的最开始的位置
	pFun = (Fun)*((int*)*(int*)(&d)+0);  // Base::f()
	pFun();
    pFun = (Fun)*((int*)*(int*)(&d)+1);  // Base::g()
	pFun();
    pFun = (Fun)*((int*)*(int*)(&d)+2);  // Base::h()
	pFun();
	pFun = (Fun)*((int*)*(int*)(&d)+3);  // Derive::f1()
	pFun();
    pFun = (Fun)*((int*)*(int*)(&d)+4);  // Derive::g1()
	pFun();
    pFun = (Fun)*((int*)*(int*)(&d)+5);  // Derive::h1()
	pFun();


	system("pause");
	return 0;
}
探究C++对象模型_第3张图片

没有看到 type_info的影子,这也正是我们以往心目中Vtable的内存位置

这是神马情况?上文的图在胡扯?

再看下面代码,

测试代码(vc8.0执行正常,vc6会报错,可能对象模型不一致)

#include "iostream"
#include "string"


using namespace std;
class Aclass
{
public:
     int a;
    virtual void setA(int tmp)
    {
        a=tmp;
        cout<<a<<endl;
    }
};
class Bclass:public Aclass
{
public:
    virtual void setA(int tmp)
    {
        a=tmp+10;
        cout<<a<<endl;
    }
public:
    void print()
    {
       cout<<a<<endl;
	}
};
class Cclass:public Bclass
{
};
typedef unsigned long DWORD;

struct TypeDescriptor
{
    DWORD ptrToVTable;
    DWORD spare;
    char name[8];
};

struct PMD
{

    int mdisp;  //member displacement

    int pdisp;  //vbtable displacement

    int vdisp;  //displacement inside vbtable

};

struct RTTIBaseClassDescriptor
 
{
 
   struct TypeDescriptor* pTypeDescriptor; //type descriptor of the class

    DWORD numContainedBases; //number of nested classes following in the Base Class Array

    struct PMD where;        //pointer-to-member displacement info

    DWORD attributes;        //flags, usually 0

};

struct RTTIClassHierarchyDescriptor
{

    DWORD signature;      //always zero?

    DWORD attributes;     //bit 0 set = multiple inheritance, bit 1 set = virtual inheritance

    DWORD numBaseClasses; //number of classes in pBaseClassArray
 
    struct RTTIBaseClassArray* pBaseClassArray;
 
 };
 
 struct RTTICompleteObjectLocator
 
 {
 
     DWORD signature; //always zero ?
 
     DWORD offset;    //offset of this vtable in the complete class
 
     DWORD cdOffset;  //constructor displacement offset
 
     struct TypeDescriptor* pTypeDescriptor; //TypeDescriptor of the complete class
 
     struct RTTIClassHierarchyDescriptor* pClassDescriptor; //describes inheritance hierarchy
 
 
 };
 
 
 int main( )
 {
	 Aclass* ptra=new Bclass;
	 int ** ptrvf=(int**)(ptra);



	 RTTICompleteObjectLocator str = *((RTTICompleteObjectLocator*)(*((int*)ptrvf[0]-1))); 

	 //abstract class name from RTTI
	 string classname(str.pTypeDescriptor->name);
	 classname=classname.substr(4,classname.find("@@")-4);
	 cout<<classname<<endl;
	 system("pause");
	 return 0;
 }

哈哈,原来在我们通常所认为VTable的前面的四个字节,你怎么看?

感谢 点击打开链接 的文章<<对象与对象的类型信息----获取对象的RTTI信息>>,引用了你的代码。





你可能感兴趣的:(探究C++对象模型)