程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 探究C++對象模型

探究C++對象模型

編輯:C++入門知識

先引用兩句名言作為開場白:

"C++老手分兩類:一種人把語言用得爛熟,OO觀念也有;另一種人不但如此,還對於台面下的機制,如編譯器合成的default constructor、object的內存布局等有莫大的興趣。"

"了解C++對象模型,絕對有助於你在語言本身以及面向對象觀念兩方面的層次提升。"

首先以Point類為例

 


再看下對象模型

 


這個模型好像跟我們以往的認知有些不一致呀,vtable首四個字節怎麼是type_info的指針?type_info是RTTI的內容,是編譯器用來進行類型識別的,它到底存不存在呢?

用代碼測試一下


[cpp]
// 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; 

// 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;
}
 

沒有看到 type_info的影子,這也正是我們以往心目中Vtable的內存位置

這是神馬情況?上文的圖在胡扯?

再看下面代碼,

測試代碼(vc8.0執行正常,vc6會報錯,可能對象模型不一致)

 

[cpp]
#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; 
 } 

#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;
 }

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved