C++类的实例的内存布局-阅《Reverse C++》有获(2)

一、指向虚函数表的指针(vfptr)是被添加在最前面的,而在虚函数表里面,各个虚函数是按照其声明的顺序排列的。
为了验证,同样的在上面的例子里修改,直接添加一个虚函数进去:

#include
using namespace std;

class A{
  private:
    char ch;
    int a,b;    
    
  public:
    A(){
      cout<<"调用构造函数\n";
      a=2;
      b=3;
    }
    ~A(){
      cout<<"调用析构函数\n";
    }
    
    void display(){
      cout<<"a+b="<    }
    virtual void display1(){
      cout<<"virtual function: display1()\n";
    }
};
  
int main(){
  A a;
  a.display();
  a.display1();
  
  return 0;
}


同样通过命令行编译:

E:\Programming\c_cpp>cl classA.cpp /EHsc /d1reportAllClassLayout > class.layout


从重定向的class.Layout文件中获得:

class A  size(16):
  +---
0  | {vfptr}
4  | ch
    | <alignment member> (size=3)
8  | a
12  | b
  +---

A::$vftable@:
  | &A_meta
  |  0
0  | &A::display1

A::display1 this adjustor: 0



二、当一个类是继承另一个类的话或多个类的话,派生类将每个基类都嵌入了自身,而且每个基类还都保留有自己的虚函数表。但是请注意,第一个基类的虚函数表是被派生类共享的,派生类的虚函数将会被例在基类虚函数表的后面。

同样是在上面的代码的基础上进行一翻修改:

#include
using namespace std;

class A{
  private:
    char ch;
    int a,b;    
    
  public:
    virtual void displayA(){
      cout<<"virtual function: displayA()\n";
    }
};

class B{
  private:
    char ch;
    int a,b;    
    
  public:
    virtual void displayB(){
      cout<<"virtual function: displayB()\n";
    }
};

class C: public A,public B{
  private:
    int a,b;
  public:
    void displayC(){
      cout<<"function: displayC()\n";
    }
};
  
int main(){
  C c;
  c.displayA();
  c.displayB();
  c.displayC();
  
  return 0;
}


编译后得到class.Layout文件:

class A  size(16):
  +---
0  | {vfptr}
4  | ch
    | <alignment member> (size=3)
8  | a
12  | b
  +---

A::$vftable@:
  | &A_meta
  |  0
0  | &A::displayA

A::displayA this adjustor: 0


class B  size(16):
  +---
0  | {vfptr}
4  | ch
    | <alignment member> (size=3)
8  | a
12  | b
  +---

B::$vftable@:
  | &B_meta
  |  0
0  | &B::displayB

B::displayB this adjustor: 0


这里的我们上面已经理解并实践后,我们这里主要是关注类C的结构:

class C  size(40):
  +---
  | +--- (base class A)
0  | | {vfptr}
4  | | ch
    | | <alignment member> (size=3)
8  | | a
12  | | b
  | +---
  | +--- (base class B)
16  | | {vfptr}
20  | | ch
    | | <alignment member> (size=3)
24  | | a
28  | | b
  | +---
32  | a
36  | b
  +---

C::$vftable@A@:
  | &C_meta
  |  0
0  | &A::displayA

C::$vftable@B@:
  | -16
0  | &B::displayB


留意了一下,发现嵌入的顺序也是按照继续的从左到右的顺序来的!