C++继承类内存模型

  整理一下继承关系中类的内存模型,算是自己做得一个小测试,有了解的希望可以指正一下文中可能出现的错误。
  测试环境windows,g++7.4.0。

1 普通类

1.1 没有虚函数的类

  普通的类中可能包含的元素有:普通成员变量,静态成员变量,成员函数,静态成员函数,虚函数。
  其中能够影响内存模型的有:普通成员变量,虚函数(虚函数表指针)。当然C++的内存对齐机制也会使得对象的大小改变。

#include 

using namespace std;


class book
{
private:
    int val;
    char ch_val;
    static int static_val;
    
public:
    book()
    {
        val = 4;
        ch_val = 3;
        cout<<"book constructer function\n";
    }
    
    ~book()
    {
        cout<<"book deconstructer function\n";
    }
    
    static void static_function(){}
    
    void ptr_ostream()
    {
        cout<<"size of object book\t" << sizeof(*this)<<endl;
        cout<<"address of object book\t" << this<<endl;
        cout<<"address of val\t"<<&val<<endl;
        cout<<"address of ch_val\t"<<&ch_val<<endl;
        cout<<"address of static_val\t"<<&book::static_val<<endl;
        cout<<"address of static_function\t" << &book::static_function<<endl;
    }
};

int book::static_val = 0;

int main()
{
    book b;
    b.ptr_ostream();
    return 0;
}

  上面book类的输出结果是:

book constructer function
size of object book	8
address of object book	00000054A772F8D8
address of val	00000054A772F8D8
address of ch_val	00000054A772F8DC
address of static_val	00007FF670FCA4F4
address of static_function	00007FF670FB1866
book deconstructer function

  第二行大小为8字节包含一个int4字节,一个char占1个字节,因为内存对齐的关系,最终的大小是8字节。
  第三行的对象地址和第一个成员变量的地址相同。
  第5行可以看到静态变量和静态函数的地址和类相距比较远,因为他们属于当前类,而不是属于某单个实例。
  通过g++ -fdump-class-hierarchy main.cpp可以看到类的结构,整体大小为5字节,内存对齐之后为8字节。

Class book
   size=8 align=4
   base size=5 base align=4
book (0x0x6fffe70d8c0) 0

C++继承类内存模型_第1张图片

1.2 有虚函数的类

  为book添加两个虚函数virtual_function_rstvirtual_function_snd

#include 

using namespace std;


class book
{
private:
    int val;
    char ch_val;
    static int static_val;
    
public:
    book()
    {
        cout<<"book constructer function\n";
    }
    
    ~book()
    {
        cout<<"book deconstructer function\n";
    }
    
    static void static_function(){}
    
    virtual void virtual_function_rst()
    {
        cout<<"book virtual function first\n";
    }
    
    virtual void virtual_function_snd()
    {
        cout<<"book virtual function second\n";
    }
    
    void ptr_ostream()
    {
        cout<<"size of object book\t" << sizeof(*this)<<endl;
        cout<<"address of object book\t" << this<<endl;
        cout<<"address of val\t"<<&val<<endl;
        cout<<"address of static_val\t"<<&book::static_val<<endl;
        cout<<"address of static_function\t" << &book::static_function<<endl;
        this->virtual_function_rst();
        this->virtual_function_snd();
    }
};

int book::static_val = 0;

int main()
{
    book b;
    b.ptr_ostream();
    return 0;
}

  输出结果为:

book constructer function
size of object book	16
address of object book	00000059180FF648
address of val	00000059180FF650
address of static_val	00007FF629F4A4F4
address of static_function	00007FF629F31866
book virtual function first
book virtual function second
book deconstructer function

  通过g++ -fdump-class-hierarchy main.cpp可以看到类的结构。

Vtable for book
book::_ZTV4book: 4 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI4book)
16    (int (*)(...))book::virtual_function_rst
24    (int (*)(...))book::virtual_function_snd

Class book
   size=16 align=8
   base size=13 base align=8
book (0x0x6fffe70d8c0) 0
    vptr=((& book::_ZTV4book) + 16)

  从上面的输出可以看到book的大小为16,实际大小为13,16是经过内存对齐的。
  book的地址是00000059180FF648,第一个成员变量地址为00000059180FF650,可以看到二者相差8个字节,刚好一个指针的大小。这个指针便是虚函数表。该虚函数表包含当前类的所有虚函数的指针。
  知道虚函数表指针之后可以通过对地址进行重解析进行函数的访问。如下将函数ptr_ostream修改为:

void ptr_ostream()
    {
        cout<<"size of object book\t" << sizeof(*this)<<endl;
        cout<<"address of object book\t" << this<<endl;
        cout<<"address of val\t"<<&val<<endl;
        cout<<"address of static_val\t"<<&book::static_val<<endl;
        cout<<"address of static_function\t" << &book::static_function<<endl;
        
        this->virtual_function_rst();
        this->virtual_function_snd();
        
		void **vptr = (void**)(int*)*(int**)(this);
		cout<<"address of virtual table\t"<<vptr<<endl;
		int func_no = 2;
		typedef void (*virtual_func)();
		for(int i = 0;i < func_no;i++)
		{
		    //virtual_func func = (int)vptr[i];
		    //func();
		    virtual_func func = (virtual_func)(int*)vptr[i];
		    func();
		    cout<<"the "<<i<<"th virtual function address\t"<<func<<endl;
		}

  输出结果为:

book constructer function
size of object book	16
address of object book	0000005C03CFFE28
address of val	0000005C03CFFE30
address of static_val	00007FF67AFBA4F4
address of static_function	00007FF67AFA1866
book virtual function first
book virtual function second
address of virtual table	00007FF67AFB40B0
book virtual function first
the 0th virtual function address	00007FF67AFA187A
book virtual function second

  可以看到虚函数成功调用。当前类的内存模型如下(当然需要注意的是虚函数表并不是简单的结构,图只是示意图):
C++继承类内存模型_第2张图片

2 单继承类

2.1 普通单继承类

  重新创建一个类book作为类science_book的基类。

#include 

using namespace std;


class book
{
private:
    int val;
    char ch_val;

public:
    book()
    {
        ch_val = 3;
        val = 4;
        cout<<"book constructer function\n";
    }
    
    ~book()
    {
        cout<<"book deconstructer function\n";
    }
    
    void ptr_ostream()
    {
        cout<<"size of object book\t" << sizeof(*this)<<endl;
        cout<<"address of object book\t" << this<<endl;
        cout<<"address of val\t"<<(int*)&val<<endl;
        cout<<"address of ch_val\t"<<(int*)&ch_val<<endl;
    }
};

class science_book : public book
{
    char sci_val;
public:
    science_book()
    {
        sci_val = 5;
        cout<<"science book constructer function\n";
    }
    
    ~science_book()
    {
        cout<<"science book deconstructer function\n";
    }
    
    void ptr_ostream()
    {
        book::ptr_ostream();
        cout<<"size of object science book\t" << sizeof(*this)<<endl;
        cout<<"address of object science book\t" << this<<endl;
        cout<<"address of sci_val\t"<<(int*)&sci_val<<endl;
    }
};

  **构造顺序:**从下面的输出可以看到类的构造销毁顺序是:

  • 构造基类book==>构造子类science_book
  • 销毁子类science_book==>销毁子类book
book constructer function
science book constructer function
size of object book	8
address of object book	000000AA7238FAC8
address of val	000000AA7238FAC8
address of ch_val	000000AA7238FACC
size of object science book	12
address of object science book	000000AA7238FAC8
address of sci_val	000000AA7238FAD0
science book deconstructer function
book deconstructer function

  内存结构结合上面的输出可以看到子类science_book第一块内存是基类book,之后子类的内容。

Class book
   size=8 align=4
   base size=5 base align=4
book (0x0x6fffe70d8c0) 0
Class science_book
   size=8 align=4
   base size=6 base align=4
science_book (0x0x6fffe53b4c8) 0
  book (0x0x6fffe70f000) 0

  内存大小上就是基类大小+子类大小。
C++继承类内存模型_第3张图片

2.2 多层继承

  继承深度超过1的类内存结构和普通的双层继承类似。

#include 

using namespace std;

class book
{
private:
    int val;
    char ch_val;

public:
    book()
    {
        ch_val = 3;
        val = 4;
        cout<<"book constructer function\n";
    }
    
    ~book()
    {
        cout<<"book deconstructer function\n";
    }
    
    void ptr_ostream()
    {
        cout<<"size of object book\t" << sizeof(*this)<<endl;
        cout<<"address of object book\t" << this<<endl;
        cout<<"address of val\t"<<(int*)&val<<endl;
        cout<<"address of ch_val\t"<<(int*)&ch_val<<endl;
    }
};

class science_book : public book
{
    char sci_val;
public:
    science_book()
    {
        sci_val = 5;
        cout<<"science book constructer function\n";
    }
    
    ~science_book()
    {
        cout<<"science book deconstructer function\n";
    }
    
    void ptr_ostream()
    {
        book::ptr_ostream();
        cout<<"size of object science book\t" << sizeof(*this)<<endl;
        cout<<"address of object science book\t" << this<<endl;
        cout<<"address of sci_val\t"<<(int*)&sci_val<<endl;
    }
};

class task_book : public science_book
{
    char tsk_val;
public:
    task_book()
    {
        tsk_val = 5;
        cout<<"task book constructer function\n";
    }
    
    ~task_book()
    {
        cout<<"task book deconstructer function\n";
    }
    
    void ptr_ostream()
    {
        science_book::ptr_ostream();
        cout<<"size of object task book\t" << sizeof(*this)<<endl;
        cout<<"address of object task book\t" << this<<endl;
        cout<<"address of tsk_val\t"<<(int*)&tsk_val<<endl;
    }
};

  从下面的输出可以看出其类个构造顺序是先构造基类,再构造派生类。先销毁派生类,在销毁基类。

book constructer function
science book constructer function
task book constructer function
size of object book	8
address of object book	000000725BCFFC48
address of val	000000725BCFFC48
address of ch_val	000000725BCFFC4C
size of object science book	12
address of object science book	000000725BCFFC48
address of sci_val	000000725BCFFC50
size of object task book	16
address of object task book	000000725BCFFC48
address of tsk_val	000000725BCFFC54
task book deconstructer function
science book deconstructer function
book deconstructer function

  从下面得到的内存大小和实际输出的内存大小不一致,具体原因不是很清楚。

Class book
   size=8 align=4
   base size=5 base align=4
book (0x0x6fffe70d8c0) 0
Class science_book
   size=8 align=4
   base size=6 base align=4
science_book (0x0x6fffe53b4c8) 0
  book (0x0x6fffe70f000) 0
Class task_book
   size=8 align=4
   base size=7 base align=4
task_book (0x0x6fffe53b9a8) 0
  science_book (0x0x6fffe53ba10) 0
    book (0x0x6fffe70f8a0) 0

  下面的内存结构是根据实际输出的内存地址构建。
C++继承类内存模型_第4张图片

2.3 包含虚函数的继承类

  新建三个类:book,science_book,task_book,其中bookscience_book的基类,science_booktask_book的基类。

  • book中实现了三个虚函数book_virtual_rst,book_virtual_snd,book_virtual_snd
  • science_book重写了父类的book_virtual_snd,book_virtual_thd,新添加了一个虚函数sci_book_virtual
  • task_book重写了父类的book_virtual_thd,新添加了一个虚函数task_virtual

  代码如下:

#include 

using namespace std;

class book
{
private:
    int val;
    char ch_val;

public:
    book()
    {
        ch_val = 3;
        val = 4;
        cout<<"book constructer function\n";
    }
    
    ~book()
    {
        cout<<"book deconstructer function\n";
    }
    
    
    virtual void book_virtual_rst()
    {
        cout<<"book virtual first!"<<endl;
    }
    
    virtual void book_virtual_snd()
    {
        cout<<"book virtual second!"<<endl;
    }
    
    virtual void book_virtual_thd()
    {
        cout<<"book virtual third!"<<endl;
    }
    
    void ptr_ostream()
    {
        book *ptr = &(*this);
        cout<<"\nsize of object book\t" << sizeof(*ptr)<<endl;
        cout<<"address of object book\t" << ptr<<endl;
        cout<<"address of val\t"<<(int*)&val<<endl;
        cout<<"address of ch_val\t"<<(int*)&ch_val<<endl;
        void **vptr = (void**)(int*)*(int**)(ptr);
		cout<<"book address of virtual table\t"<<vptr<<endl;
		int func_no = 5;
		typedef void (*virtual_func)();
		for(int i = 0;i < func_no;i++)
		{
		    //virtual_func func = (int)vptr[i];
		    //func();
		    virtual_func func = (virtual_func)(int*)vptr[i];
		    func();
		    cout<<"the "<<i<<"th virtual function address\t"<<func<<endl;
		}
    }
};

class science_book : public book
{
    char sci_val;
public:
    science_book()
    {
        sci_val = 5;
        cout<<"science book constructer function\n";
    }
    
    ~science_book()
    {
        cout<<"science book deconstructer function\n";
    }
    
    virtual void book_virtual_snd()
    {
        cout<<"science book virtual second!"<<endl;
    }
    
    virtual void book_virtual_thd()
    {
        cout<<"science book virtual third!"<<endl;
    }
    
    virtual void sci_book_virtual()
    {
        cout<<"science book virtual function!"<<endl;
    }
    
    void ptr_ostream()
    {
        book::ptr_ostream();
        science_book *ptr = &(*this);
        cout<<"\nsize of object science book\t" << sizeof(*ptr)<<endl;
        cout<<"address of object science book\t" << ptr<<endl;
        cout<<"address of sci_val\t"<<(int*)&sci_val<<endl;
        void **vptr = (void**)(int*)*(int**)(ptr);
		cout<<"science book address of virtual table\t"<<vptr<<endl;
		int func_no = 5;
		typedef void (*virtual_func)();
		for(int i = 0;i < func_no;i++)
		{
		    //virtual_func func = (int)vptr[i];
		    //func();
		    virtual_func func = (virtual_func)(int*)vptr[i];
		    func();
		    cout<<"the "<<i<<"th virtual function address\t"<<func<<endl;
		}
    }
};

class task_book : public science_book
{
    char tsk_val;
public:
    task_book()
    {
        tsk_val = 5;
        cout<<"task book constructer function\n";
    }
    
    ~task_book()
    {
        cout<<"task book deconstructer function\n";
    }
    
    virtual void book_virtual_thd()
    {
        cout<<"task book virtual third!"<<endl;
    }
    
    virtual void task_virtual()
    {
        cout<<"task book virtual function!"<<endl;
    }
    
    void ptr_ostream()
    {
        science_book::ptr_ostream();
        task_book *ptr = &(*this);
        cout<<"\nsize of object task book\t" << sizeof(*ptr)<<endl;
        cout<<"address of object task book\t" << ptr<<endl;
        cout<<"address of tsk_val\t"<<(int*)&tsk_val<<endl;
        void **vptr = (void**)(int*)*(int**)(ptr);
		cout<<"task book address of virtual table\t"<<vptr<<endl;
		int func_no = 5;
		typedef void (*virtual_func)();
		for(int i = 0;i < func_no;i++)
		{
		    //virtual_func func = (int)vptr[i];
		    //func();
		    virtual_func func = (virtual_func)(int*)vptr[i];
		    func();
		    cout<<"the "<<i<<"th virtual function address\t"<<func<<endl;
		}
    } 
};

  从上面构建的类来看book只包含3个虚函数,science_book只包含四个虚函数,task_book而三个类中func_no都设为5。这个先注意下,下面配合g++的输出进行解释。
  程序的输出结果为:

book constructer function
science book constructer function
task book constructer function

size of object book	16
address of object book	000000ECDDEFFB98
address of val	000000ECDDEFFBA0
address of ch_val	000000ECDDEFFBA4
book address of virtual table	00007FF78B793FF8
book virtual first!
the 0th virtual function address	00007FF78B7818D9
science book virtual second!
the 1th virtual function address	00007FF78B7818CF
task book virtual third!
the 2th virtual function address	00007FF78B7818C5
science book virtual function!
the 3th virtual function address	00007FF78B7818B1
task book virtual function!
the 4th virtual function address	00007FF78B7818B6

size of object science book	24
address of object science book	000000ECDDEFFB98
address of sci_val	000000ECDDEFFBA8
science book address of virtual table	00007FF78B793FF8
book virtual first!
the 0th virtual function address	00007FF78B7818D9
science book virtual second!
the 1th virtual function address	00007FF78B7818CF
task book virtual third!
the 2th virtual function address	00007FF78B7818C5
science book virtual function!
the 3th virtual function address	00007FF78B7818B1
task book virtual function!
the 4th virtual function address	00007FF78B7818B6

size of object task book	32
address of object task book	000000ECDDEFFB98
address of tsk_val	000000ECDDEFFBB0
task book address of virtual table	00007FF78B793FF8
book virtual first!
the 0th virtual function address	00007FF78B7818D9
science book virtual second!
the 1th virtual function address	00007FF78B7818CF
task book virtual third!
the 2th virtual function address	00007FF78B7818C5
science book virtual function!
the 3th virtual function address	00007FF78B7818B1
task book virtual function!
the 4th virtual function address	00007FF78B7818B6
task book virtual third!
task book deconstructer function
science book deconstructer function
book deconstructer function

  下面是g++输出的虚函数表的内容,和最终测试出来的内容有一定冲突并不是完全准确:

Vtable for book
book::_ZTV4book: 5 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI4book)
16    (int (*)(...))book::book_virtual_rst
24    (int (*)(...))book::book_virtual_snd
32    (int (*)(...))book::book_virtual_thd

Class book
   size=16 align=8
   base size=13 base align=8
book (0x0x6fffe70d8c0) 0
    vptr=((& book::_ZTV4book) + 16)
Vtable for science_book
science_book::_ZTV12science_book: 6 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI12science_book)
16    (int (*)(...))book::book_virtual_rst
24    (int (*)(...))science_book::book_virtual_snd
32    (int (*)(...))science_book::book_virtual_thd
40    (int (*)(...))science_book::sci_book_virtual

Class science_book
   size=16 align=8
   base size=14 base align=8
science_book (0x0x6fffe53b598) 0
    vptr=((& science_book::_ZTV12science_book) + 16)
  book (0x0x6fffe70f1e0) 0
      primary-for science_book (0x0x6fffe53b598)
Vtable for task_book
task_book::_ZTV9task_book: 7 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI9task_book)
16    (int (*)(...))book::book_virtual_rst
24    (int (*)(...))science_book::book_virtual_snd
32    (int (*)(...))task_book::book_virtual_thd
40    (int (*)(...))science_book::sci_book_virtual
48    (int (*)(...))task_book::task_virtual

Class task_book
   size=16 align=8
   base size=15 base align=8
task_book (0x0x6fffe53bb48) 0
    vptr=((& task_book::_ZTV9task_book) + 16)
  science_book (0x0x6fffe53bbb0) 0
      primary-for task_book (0x0x6fffe53bb48)
    book (0x0x6fffe70fc60) 0
        primary-for science_book (0x0x6fffe53bbb0)

  下面是根据实际测试输出得到的内存格式:
C++继承类内存模型_第5张图片

  从内存结构中可以看到整个类中只包含一个虚函数表指针,虚函数表中会将子类中重写的方法的函数地址替换掉父类中的虚函数地址。上面每个ptr_ostream函数中使用5是为了验证整个类中只有一个虚函数指针。
  既然如此,是否可以通过父类的指针访问子类的函数。

task_book tk;
book* ptr = &tk;
ptr->task_virtual();

  实际上,上面的代码无法通过编译期,虽然仅仅从运行时来讲是可以的,但是编译器进行类型检查会报错。

  另外猜测一下g++输出的虚函数表的内容和实际不同的原因可能是:该输出只是每个类的内存结构,而实际测试中是针对实际的类实例的,即测试得到的是类实例的内存结构。也就是说如果实例化一个book或者science_book的对象,得到的虚函数表结构应该和该输出结果类似。

3 多继承类

3.1 普通多继承类

  构建三个基础类:camera,communicator,player,一个子类phone继承自上面的三个类。

#include 
using namespace std;

class communicator
{
    int com_val;
    char com_ch;
    
public:
    communicator()
    {
        cout<<"call communicator constructor!\n";
    }
    
    ~communicator()
    {
        cout<<"call communicator desctructor!\n";
    }
    
    void ptr_ostream()
    {
        communicator* ptr = &(*this);
        cout<<endl;
        cout<<"size of object communicator\t" << sizeof(*ptr)<<endl;
        cout<<"address of object communicator\t" << ptr<<endl;
        cout<<"address of com_val\t"<<(int*)&com_val<<endl;
        cout<<"address of com_ch\t"<<(int*)&com_ch<<endl;
    }
};

class camera
{
    char cam_ch;
    
public:
    camera()
    {
        cout<<"call camera constructor!\n";
    }
    
    ~camera()
    {
        cout<<"call camera desctructor!\n";
    }
    
    void ptr_ostream()
    {
        camera* ptr = &(*this);
        cout<<endl;
        cout<<"size of object camera\t" << sizeof(*ptr)<<endl;
        cout<<"address of object camera\t" << ptr<<endl;
        cout<<"address of cam_ch\t"<<(int*)&cam_ch<<endl;
    }
};

class player
{
    char play_ch;
    
public:
    player()
    {
        cout<<"call player constructor!\n";
    }
    
    ~player()
    {
        cout<<"call player desctructor!\n";
    }
    
    void ptr_ostream()
    {
        player* ptr = &(*this);
        cout<<endl;
        cout<<"size of object player\t" << sizeof(*ptr)<<endl;
        cout<<"address of object player\t" << ptr<<endl;
        cout<<"address of play_ch\t"<<(int*)&play_ch<<endl;
    }
};


class phone : public communicator, public camera, public player
{
    char ph_ch;
public:
    phone()
    {
        cout<<"call phone constructor!\n";
    }
    
    ~phone()
    {
        cout<<"call phone desctructor!\n";
    }
    
    void ptr_ostream()
    {
        communicator::ptr_ostream();
        camera::ptr_ostream();
        player::ptr_ostream();
        
        phone* ptr = &(*this);
        cout<<endl;
        cout<<"size of object phone\t" << sizeof(*ptr)<<endl;
        cout<<"address of object phone\t" << ptr<<endl;
        cout<<"address of play_ch\t"<<(int*)&ph_ch<<endl;
    }
};

  上面结果的输出如下:

call communicator constructor!
call camera constructor!
call player constructor!
call phone constructor!

size of object communicator	8
address of object communicator	000000BEC44FFBB8
address of com_val	000000BEC44FFBB8
address of com_ch	000000BEC44FFBBC

size of object camera	1
address of object camera	000000BEC44FFBC0
address of cam_ch	000000BEC44FFBC0

size of object player	1
address of object player	000000BEC44FFBC1
address of play_ch	000000BEC44FFBC1

size of object phone	12
address of object phone	000000BEC44FFBB8
address of play_ch	000000BEC44FFBC2
call phone desctructor!
call player desctructor!
call camera desctructor!
call communicator desctructor!

  通过g++ -fdump-class-hierarchy得到的内存模型如下:

Class communicator
   size=8 align=4
   base size=5 base align=4
communicator (0x0x6fffe70d8c0) 0
Class camera
   size=1 align=1
   base size=1 base align=1
camera (0x0x6fffe70ee80) 0
Class player
   size=1 align=1
   base size=1 base align=1
player (0x0x6fffe70f5a0) 0
Class phone
   size=8 align=4
   base size=8 base align=4
phone (0x0x6fffe321860) 0
  communicator (0x0x6fffe70fb40) 0
  camera (0x0x6fffe70fba0) 5
  player (0x0x6fffe70fc00) 6

  根据内存地址构建出的内存结构如下:
C++继承类内存模型_第6张图片

3.2 包含虚函数的多继承类

  现在给上面的每个类添加两个虚函数,子类phone重新其中一个:

  • communicator添加com_vir_rst和com_vir_snd
  • camera添加cam_vir_rst和cam_vir_snd
  • player添加play_vir_rst和play_vir_snd
  • phone添加ph_virtual,重写com_vir_rst, play_vir_rst, cam_vir_rst
#include 
using namespace std;

class communicator
{
    int com_val;
    char com_ch;
    
public:
    communicator()
    {
        cout<<"call communicator constructor!\n";
    }
    
    ~communicator()
    {
        cout<<"call communicator desctructor!\n";
    }
    
    virtual void com_vir_rst()
    {
        cout<<"communicator virtual first!\n";
    }
    
    virtual void com_vir_snd()
    {
        cout<<"communicator virtual second!\n";
    }
    
    void ptr_ostream()
    {
        communicator* ptr = &(*this);
        cout<<endl;
        cout<<"size of object communicator\t" << sizeof(*ptr)<<endl;
        cout<<"address of object communicator\t" << ptr<<endl;
        cout<<"address of com_val\t"<<(int*)&com_val<<endl;
        cout<<"address of com_ch\t"<<(int*)&com_ch<<endl;
        
        void **vptr = (void**)(int*)*(int**)(ptr);
		cout<<"communicator address of virtual table\t"<<vptr<<endl;
		int func_no = 6;
		typedef void (*virtual_func)();
		for(int i = 0;i < func_no;i++)
		{
		    if(i == 3) continue;
		    virtual_func func = (virtual_func)(int*)vptr[i];
		    func();
		    cout<<"the "<<i<<"th virtual function address\t"<<func<<endl;
		}
    }
};

class camera
{
    char cam_ch;
    
public:
    camera()
    {
        cout<<"call camera constructor!\n";
    }
    
    ~camera()
    {
        cout<<"call camera desctructor!\n";
    }
    
    virtual void cam_vir_rst()
    {
        cout<<"camera virtual first!\n";
    }
    
    virtual void cam_vir_snd()
    {
        cout<<"camera virtual second!\n";
    }
    
    void ptr_ostream()
    {
        camera* ptr = &(*this);
        cout<<endl;
        cout<<"size of object camera\t" << sizeof(*ptr)<<endl;
        cout<<"address of object camera\t" << ptr<<endl;
        cout<<"address of cam_ch\t"<<(int*)&cam_ch<<endl;
        void **vptr = (void**)(int*)*(int**)(ptr);
		cout<<"camera address of virtual table\t"<<vptr<<endl;
		
		int func_no = 2;
		typedef void (*virtual_func)();
		for(int i = 0;i < func_no;i++)
		{
		    virtual_func func = (virtual_func)(int*)vptr[i];
		    func();
		    cout<<"the "<<i<<"th virtual function address\t"<<func<<endl;
		}
    }
};

class player
{
    char play_ch;
    
public:
    player()
    {
        cout<<"call player constructor!\n";
    }
    
    ~player()
    {
        cout<<"call player desctructor!\n";
    }
    
    virtual void play_vir_rst()
    {
        cout<<"player virtual first!\n";
    }
    
    virtual void play_vir_snd()
    {
        cout<<"player virtual second!\n";
    }
    
    void ptr_ostream()
    {
        player* ptr = &(*this);
        cout<<endl;
        cout<<"size of object player\t" << sizeof(*ptr)<<endl;
        cout<<"address of object player\t" << ptr<<endl;
        cout<<"address of play_ch\t"<<(int*)&play_ch<<endl;
        
        void **vptr = (void**)(int*)*(int**)(ptr);
		cout<<"player address of virtual table\t"<<vptr<<endl;
		
		int func_no = 2;
		typedef void (*virtual_func)();
		for(int i = 0;i < func_no;i++)
		{
		    virtual_func func = (virtual_func)(int*)vptr[i];
		    func();
		    cout<<"the "<<i<<"th virtual function address\t"<<func<<endl;
		}
    }
};


class phone : public communicator, public camera, public player
{
    char ph_ch;
public:
    phone()
    {
        cout<<"call phone constructor!\n";
    }
    
    ~phone()
    {
        cout<<"call phone desctructor!\n";
    }
    
    virtual void ph_virtual()
    {
        cout<<"phone virtual!\n";
    }
    
    virtual void com_vir_rst()
    {
        cout<<"phone communicator virtual first!\n";
    }
    
    virtual void cam_vir_rst()
    {
        cout<<"phone camera virtual first!\n";
    }
    
    virtual void play_vir_rst()
    {
        cout<<"phone player virtual first!\n";
    }
    
    void ptr_ostream()
    {
        communicator::ptr_ostream();
        camera::ptr_ostream();
        player::ptr_ostream();
        
        phone* ptr = &(*this);
        cout<<endl;
        cout<<"size of object phone\t" << sizeof(*ptr)<<endl;
        cout<<"address of object phone\t" << ptr<<endl;
        cout<<"address of play_ch\t"<<(int*)&ph_ch<<endl;
        
        void **vptr = (void**)(int*)*(int**)(ptr);
		cout<<"phone address of virtual table\t"<<vptr<<endl;
		int func_no = 3;
		typedef void (*virtual_func)();
		for(int i = 0;i < func_no;i++)
		{
		    virtual_func func = (virtual_func)(int*)vptr[i];
		    func();
		    cout<<"the "<<i<<"th virtual function address\t"<<func<<endl;
		}
    }
};

  code输出结果如下:

call communicator constructor!
call camera constructor!
call player constructor!
call phone constructor!

size of object communicator	16
address of object communicator	000000BA45DCF7C8
address of com_val	000000BA45DCF7D0
address of com_ch	000000BA45DCF7D4
communicator address of virtual table	00007FF666DA3FC0
phone communicator virtual first!
the 0th virtual function address	00007FF666D9191F
communicator virtual second!
the 1th virtual function address	00007FF666D91929
phone virtual!
the 2th virtual function address	00007FF666D9191A
phone player virtual first!
the 4th virtual function address	00007FF666D91938
player virtual second!
the 5th virtual function address	00007FF666D91947

size of object camera	16
address of object camera	000000BA45DCF7D8
address of cam_ch	000000BA45DCF7E0
camera address of virtual table	00007FF666DA3E98
phone camera virtual first!
the 0th virtual function address	00007FF666D9193D
camera virtual second!
the 1th virtual function address	00007FF666D9192E

size of object player	16
address of object player	000000BA45DCF7E8
address of play_ch	000000BA45DCF7F0
player address of virtual table	00007FF666DA3FE0
phone player virtual first!
the 0th virtual function address	00007FF666D91938
player virtual second!
the 1th virtual function address	00007FF666D91947

size of object phone	56
address of object phone	000000BA45DCF7C8
address of play_ch	000000BA45DCF7F8
phone address of virtual table	00007FF666DA3FC0
phone communicator virtual first!
the 0th virtual function address	00007FF666D9191F
communicator virtual second!
the 1th virtual function address	00007FF666D91929
phone virtual!
the 2th virtual function address	00007FF666D9191A
call phone desctructor!
call player desctructor!
call camera desctructor!
call communicator desctructor!

  通过g++参数得到的类结构如下:

Vtable for communicator
communicator::_ZTV12communicator: 4 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI12communicator)
16    (int (*)(...))communicator::com_vir_rst
24    (int (*)(...))communicator::com_vir_snd

Class communicator
   size=16 align=8
   base size=13 base align=8
communicator (0x0x6fffe70d8c0) 0
    vptr=((& communicator::_ZTV12communicator) + 16)
Vtable for camera
camera::_ZTV6camera: 4 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI6camera)
16    (int (*)(...))camera::cam_vir_rst
24    (int (*)(...))camera::cam_vir_snd

Class camera
   size=16 align=8
   base size=9 base align=8
camera (0x0x6fffe70f540) 0
    vptr=((& camera::_ZTV6camera) + 16)
Vtable for player
player::_ZTV6player: 4 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI6player)
16    (int (*)(...))player::play_vir_rst
24    (int (*)(...))player::play_vir_snd

Class player
   size=16 align=8
   base size=9 base align=8
player (0x0x6fffe70ff60) 0
    vptr=((& player::_ZTV6player) + 16)
Vtable for phone
phone::_ZTV5phone: 15 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI5phone)
16    (int (*)(...))phone::com_vir_rst
24    (int (*)(...))communicator::com_vir_snd
32    (int (*)(...))phone::ph_virtual
40    (int (*)(...))phone::cam_vir_rst
48    (int (*)(...))phone::play_vir_rst
56    (int (*)(...))-16
64    (int (*)(...))(& _ZTI5phone)
72    (int (*)(...))phone::_ZThn16_N5phone11cam_vir_rstEv
80    (int (*)(...))camera::cam_vir_snd
88    (int (*)(...))-32
96    (int (*)(...))(& _ZTI5phone)
104   (int (*)(...))phone::_ZThn32_N5phone12play_vir_rstEv
112   (int (*)(...))player::play_vir_snd

Class phone
   size=48 align=8
   base size=42 base align=8
phone (0x0x6fffe321b30) 0
    vptr=((& phone::_ZTV5phone) + 16)
  communicator (0x0x6fffe2806c0) 0
      primary-for phone (0x0x6fffe321b30)
  camera (0x0x6fffe280720) 16
      vptr=((& phone::_ZTV5phone) + 72)
  player (0x0x6fffe280780) 32
      vptr=((& phone::_ZTV5phone) + 104)

  通过程序日志和调试构建的类的内存结构如下:
C++继承类内存模型_第7张图片

  可以看到多继承体系中每个基类都会有一个虚函数表指针,每个虚函数表会将子类重写的函数替换掉基类中的虚函数指针,并且会在第一个继承类中即communicator中将子类的虚函数指针添加到该表中。另外可以看到途中communicator中还有额外的player::play_vir_rst等两个函数指针,这是我通过调试得到的结果,不知道具体含义为何!(紫色部分为RTTI类型相关信息)

3.3 菱形继承类

  菱形继承,这里创建四个类hardware,camera,communicator,phone

  • hardware作为公共基类,拥有两个成员变量had_chhad_val,三个虚函数had_rst,had_snd,had_thd
  • camera的基类为hardware,拥有一个成员变量cam_ch,和两个虚函数cam_rst,cam_snd,重写基类虚函数had_rst;
  • communicator的基类为hardware,拥有一个成员变量com_ch,和两个虚函数com_rst,com_snd,重写基类虚函数had_rst
  • phone的基类为communicatorcamera,拥有一个成员变量ph_ch,和一个虚函数ph_virtual,重写基类中的虚函数cam_rst,com_rst

C++继承类内存模型_第8张图片

3.3.1 非虚继承

  实现代码如下:

#include 
using namespace std;

class hardware
{
    char hd_ch;
    int hd_val;

public:
    hardware()
    {
        cout<<"call hardware constructor!\n";
    }
    
    ~hardware()
    {
        cout<<"call hardware destructor!\n";
    }
    
    virtual void had_rst()
    {
        cout<<"hardware virtual first!\n";
    }
    
    virtual void had_snd()
    {
        cout<<"hardware virtual second!\n";
    }
    
    virtual void had_thd()
    {
        cout<<"hardware virtual third!\n";
    }
    
    void ptr_ostream(int func_no)
    {
        hardware* ptr = &(*this);
        cout<<endl;
        cout<<"size of object hardware\t" << sizeof(*ptr)<<endl;
        cout<<"address of object hardware\t" << ptr<<endl;
        cout<<"address of hd_ch\t"<<(int*)&hd_ch<<endl;
        cout<<"address of hd_val\t"<<(int*)&hd_val<<endl;
        void **vptr = (void**)(int*)*(int**)(ptr);
		cout<<"hardware address of virtual table\t"<<vptr<<endl;
		
		typedef void (*virtual_func)();
		for(int i = 0;i < func_no;i++)
		{
		    virtual_func func = (virtual_func)(int*)vptr[i];
		    func();
		    cout<<"the "<<i<<"th virtual function address\t"<<func<<endl;
		}
    }
};

class communicator : public hardware
{
    char com_ch;
    
public:
    communicator()
    {
        cout<<"call communicator constructor!\n";
    }
    
    ~communicator()
    {
        cout<<"call communicator desctructor!\n";
    }
    
    virtual void had_rst()
    {
        cout<<"communicator hadware virtual first!\n";
    }
    
    virtual void com_rst()
    {
        cout<<"communicator virtual first!\n";
    }
    
    virtual void com_snd()
    {
        cout<<"communicator virtual second!\n";
    }
    
    void ptr_ostream()
    {
        communicator* ptr = &(*this);
        cout<<endl;
        cout<<"size of object communicator\t" << sizeof(*ptr)<<endl;
        cout<<"address of object communicator\t" << ptr<<endl;
        cout<<"address of com_ch\t"<<(int*)&com_ch<<endl;
    }
};

class camera : public hardware
{
    char cam_ch;
    
public:
    camera()
    {
        cout<<"call camera constructor!\n";
    }
    
    ~camera()
    {
        cout<<"call camera desctructor!\n";
    }
    
    virtual void had_rst()
    {
        cout<<"camera hadware virtual first!\n";
    }
    
    virtual void cam_rst()
    {
        cout<<"camera virtual first!\n";
    }
    
    virtual void cam_snd()
    {
        cout<<"camera virtual second!\n";
    }
    
    void ptr_ostream()
    {
        camera* ptr = &(*this);
        cout<<endl;
        cout<<"size of object camera\t" << sizeof(*ptr)<<endl;
        cout<<"address of object camera\t" << ptr<<endl;
        cout<<"address of cam_ch\t"<<(int*)&cam_ch<<endl;
        void **vptr = (void**)(int*)*(int**)(ptr);
		cout<<"camera address of virtual table\t"<<vptr<<endl;
    }
};

class phone : public communicator, public camera
{
    char ph_ch;
public:
    phone()
    {
        cout<<"call phone constructor!\n";
    }
    
    ~phone()
    {
        cout<<"call phone desctructor!\n";
    }
    
    virtual void ph_virtual()
    {
        cout<<"phone virtual!\n";
    }
    
    virtual void com_rst()
    {
        cout<<"phone communicator virtual first!\n";
    }
    
    virtual void cam_rst()
    {
        cout<<"phone camera virtual first!\n";
    }
    
    void ptr_ostream()
    {
        communicator::hardware::ptr_ostream(6);
        camera::hardware::ptr_ostream(5);
        communicator::ptr_ostream();
        camera::ptr_ostream();
        
        phone* ptr = &(*this);
        cout<<endl;
        cout<<"size of object phone\t" << sizeof(*ptr)<<endl;
        cout<<"address of object phone\t" << ptr<<endl;
        cout<<"address of play_ch\t"<<(int*)&ph_ch<<endl;
    }
};

  输出结果为:

call hardware constructor!
call communicator constructor!
call hardware constructor!
call camera constructor!
call phone constructor!

size of object hardware	16
address of object hardware	000000BB654FFC48
address of hd_ch	000000BB654FFC50
address of hd_val	000000BB654FFC54
hardware address of virtual table	00007FF7E08CC420
communicator hadware virtual first!
the 0th virtual function address	00007FF7E08C1127
hardware virtual second!
the 1th virtual function address	00007FF7E08C1299
hardware virtual third!
the 2th virtual function address	00007FF7E08C124E
phone communicator virtual first!
the 3th virtual function address	00007FF7E08C1005
communicator virtual second!
the 4th virtual function address	00007FF7E08C101E
phone virtual!
the 5th virtual function address	00007FF7E08C100A

size of object hardware	16
address of object hardware	000000BB654FFC60
address of hd_ch	000000BB654FFC68
address of hd_val	000000BB654FFC6C
hardware address of virtual table	00007FF7E08CC3C0
camera hadware virtual first!
the 0th virtual function address	00007FF7E08C11EA
hardware virtual second!
the 1th virtual function address	00007FF7E08C1299
hardware virtual third!
the 2th virtual function address	00007FF7E08C124E
phone camera virtual first!
the 3th virtual function address	00007FF7E08C1217
camera virtual second!
the 4th virtual function address	00007FF7E08C1186

size of object communicator	24
address of object communicator	000000BB654FFC48
address of com_ch	000000BB654FFC58

size of object camera	24
address of object camera	000000BB654FFC60
address of cam_ch	000000BB654FFC70
camera address of virtual table	00007FF7E08CC3C0

size of object phone	56
address of object phone	000000BB654FFC48
address of play_ch	000000BB654FFC78
call phone desctructor!
call camera desctructor!
call hardware destructor!
call communicator desctructor!
call hardware destructor!

  通过g++参数分析结构直接报错:

G:\tmp\tmp>g++ -fdump-class-hierarchy vvpmult.hpp
vvpmult.hpp: In member function 'void phone::ptr_ostream()':
vvpmult.hpp:169:46: error: 'hardware' is an ambiguous base of 'phone'
         communicator::hardware::ptr_ostream(6);
                                              ^
vvpmult.hpp:170:40: error: 'hardware' is an ambiguous base of 'phone'
         camera::hardware::ptr_ostream(5);

  根据内存地址构建的类结构如下:
C++继承类内存模型_第9张图片

3.3.2 虚继承

  虚继承将两个类声明修改virtual public并且删除had_rst函数的重写,因为会出现二义性:

class communicator : virtual public hardware
{
    ...
};
class camera : virtual public hardware
{
    ...
};
#include 
using namespace std;

class hardware
{
    char hd_ch;
    int hd_val;

public:
    hardware()
    {
        cout<<"call hardware constructor!\n";
    }
    
    ~hardware()
    {
        cout<<"call hardware destructor!\n";
    }
    
    virtual void had_rst()
    {
        cout<<"hardware virtual first!\n";
    }
    
    virtual void had_snd()
    {
        cout<<"hardware virtual second!\n";
    }
    
    virtual void had_thd()
    {
        cout<<"hardware virtual third!\n";
    }
    
    void ptr_ostream(int func_no)
    {
        hardware* ptr = &(*this);
        cout<<endl;
        cout<<"size of object hardware\t" << sizeof(*ptr)<<endl;
        cout<<"address of object hardware\t" << ptr<<endl;
        cout<<"address of hd_ch\t"<<(int*)&hd_ch<<endl;
        cout<<"address of hd_val\t"<<(int*)&hd_val<<endl;
        void **vptr = (void**)(int*)*(int**)(ptr);
		cout<<"hardware address of virtual table\t"<<vptr<<endl;
		
		typedef void (*virtual_func)();
		for(int i = 0;i < 3;i++)
		{
		    virtual_func func = (virtual_func)(int*)vptr[i];
		    func();
		    cout<<"the "<<i<<"th virtual function address\t"<<func<<endl;
		}
    }
};

class communicator : virtual public hardware
{
    char com_ch;
    
public:
    communicator()
    {
        cout<<"call communicator constructor!\n";
    }
    
    ~communicator()
    {
        cout<<"call communicator desctructor!\n";
    }
    
    virtual void com_rst()
    {
        cout<<"communicator virtual first!\n";
    }
    
    virtual void com_snd()
    {
        cout<<"communicator virtual second!\n";
    }
    
    void ptr_ostream()
    {
        communicator* ptr = &(*this);
        cout<<endl;
        cout<<"size of object communicator\t" << sizeof(*ptr)<<endl;
        cout<<"address of object communicator\t" << ptr<<endl;
        cout<<"address of com_ch\t"<<(int*)&com_ch<<endl;
        
        void **vptr = (void**)(int*)*(int**)(ptr);
		cout<<"hardware address of virtual table\t"<<vptr<<endl;
		
		typedef void (*virtual_func)();
		for(int i = 0;i < 3;i++)
		{
		    virtual_func func = (virtual_func)(int*)vptr[i];
		    func();
		    cout<<"the "<<i<<"th virtual function address\t"<<func<<endl;
		}
    }
};

class camera : virtual public hardware
{
    char cam_ch;
    
public:
    camera()
    {
        cout<<"call camera constructor!\n";
    }
    
    ~camera()
    {
        cout<<"call camera desctructor!\n";
    }
    
    virtual void cam_rst()
    {
        cout<<"camera virtual first!\n";
    }
    
    virtual void cam_snd()
    {
        cout<<"camera virtual second!\n";
    }
    
    void ptr_ostream()
    {
        camera* ptr = &(*this);
        cout<<endl;
        cout<<"size of object camera\t" << sizeof(*ptr)<<endl;
        cout<<"address of object camera\t" << ptr<<endl;
        cout<<"address of cam_ch\t"<<(int*)&cam_ch<<endl;
		
		void **vptr = (void**)(int*)*(int**)(ptr);
		cout<<"hardware address of virtual table\t"<<vptr<<endl;
		
		typedef void (*virtual_func)();
		for(int i = 0;i < 2;i++)
		{
		    virtual_func func = (virtual_func)(int*)vptr[i];
		    func();
		    cout<<"the "<<i<<"th virtual function address\t"<<func<<endl;
		}
    }
};

class phone : public communicator, public camera
{
    char ph_ch;
public:
    phone()
    {
        cout<<"call phone constructor!\n";
    }
    
    ~phone()
    {
        cout<<"call phone desctructor!\n";
    }
    
    virtual void ph_virtual()
    {
        cout<<"phone virtual!\n";
    }
    
    virtual void com_rst()
    {
        cout<<"phone communicator virtual first!\n";
    }
    
    virtual void cam_rst()
    {
        cout<<"phone camera virtual first!\n";
    }
    
    void ptr_ostream()
    {
        this->hardware::ptr_ostream(3);
        communicator::ptr_ostream();
        camera::ptr_ostream();
        
        phone* ptr = &(*this);
        cout<<endl;
        cout<<"size of object phone\t" << sizeof(*ptr)<<endl;
        cout<<"address of object phone\t" << ptr<<endl;
        cout<<"address of play_ch\t"<<(int*)&ph_ch<<endl;
    }
};
Vtable for hardware
hardware::_ZTV8hardware: 5 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI8hardware)
16    (int (*)(...))hardware::had_rst
24    (int (*)(...))hardware::had_snd
32    (int (*)(...))hardware::had_thd

Class hardware
   size=16 align=8
   base size=16 base align=8
hardware (0x0x6fffe70d8c0) 0
    vptr=((& hardware::_ZTV8hardware) + 16)
Vtable for communicator
communicator::_ZTV12communicator: 13 entries
0     16
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI12communicator)
24    (int (*)(...))communicator::com_rst
32    (int (*)(...))communicator::com_snd
40    0
48    0
56    0
64    (int (*)(...))-16
72    (int (*)(...))(& _ZTI12communicator)
80    (int (*)(...))hardware::had_rst
88    (int (*)(...))hardware::had_snd
96    (int (*)(...))hardware::had_thd

VTT for communicator
communicator::_ZTT12communicator: 2 entries
0     ((& communicator::_ZTV12communicator) + 24)
8     ((& communicator::_ZTV12communicator) + 80)
Vtable for camera
camera::_ZTV6camera: 13 entries
0     16
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI6camera)
24    (int (*)(...))camera::cam_rst
32    (int (*)(...))camera::cam_snd
40    0
48    0
56    0
64    (int (*)(...))-16
72    (int (*)(...))(& _ZTI6camera)
80    (int (*)(...))hardware::had_rst
88    (int (*)(...))hardware::had_snd
96    (int (*)(...))hardware::had_thd

VTT for camera
camera::_ZTT6camera: 2 entries
0     ((& camera::_ZTV6camera) + 24)
8     ((& camera::_ZTV6camera) + 80)

Class camera
   size=32 align=8
   base size=9 base align=8
camera (0x0x6fffe53be20) 0
    vptridx=0 vptr=((& camera::_ZTV6camera) + 24)
  hardware (0x0x6fffe280000) 16 virtual
      vptridx=8 vbaseoffset=-24 vptr=((& camera::_ZTV6camera) + 80)
Vtable for phone
phone::_ZTV5phone: 20 entries
0     32
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI5phone)
24    (int (*)(...))phone::com_rst
32    (int (*)(...))communicator::com_snd
40    (int (*)(...))phone::ph_virtual
48    (int (*)(...))phone::cam_rst
56    16
64    (int (*)(...))-16
72    (int (*)(...))(& _ZTI5phone)
80    (int (*)(...))phone::_ZThn16_N5phone7cam_rstEv
88    (int (*)(...))camera::cam_snd
96    0
104   0
112   0
120   (int (*)(...))-32
128   (int (*)(...))(& _ZTI5phone)
136   (int (*)(...))hardware::had_rst
144   (int (*)(...))hardware::had_snd
152   (int (*)(...))hardware::had_thd

Construction vtable for communicator (0x0x6fffe53c1c8 instance) in phone
phone::_ZTC5phone0_12communicator: 13 entries
0     32
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI12communicator)
24    (int (*)(...))communicator::com_rst
32    (int (*)(...))communicator::com_snd
40    0
48    0
56    0
64    (int (*)(...))-32
72    (int (*)(...))(& _ZTI12communicator)
80    (int (*)(...))hardware::had_rst
88    (int (*)(...))hardware::had_snd
96    (int (*)(...))hardware::had_thd

Construction vtable for camera (0x0x6fffe53c230 instance) in phone
phone::_ZTC5phone16_6camera: 13 entries
0     16
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI6camera)
24    (int (*)(...))camera::cam_rst
32    (int (*)(...))camera::cam_snd
40    0
48    0
56    0
64    (int (*)(...))-16
72    (int (*)(...))(& _ZTI6camera)
80    (int (*)(...))hardware::had_rst
88    (int (*)(...))hardware::had_snd
96    (int (*)(...))hardware::had_thd

VTT for phone
phone::_ZTT5phone: 7 entries
0     ((& phone::_ZTV5phone) + 24)
8     ((& phone::_ZTC5phone0_12communicator) + 24)
16    ((& phone::_ZTC5phone0_12communicator) + 80)
24    ((& phone::_ZTC5phone16_6camera) + 24)
32    ((& phone::_ZTC5phone16_6camera) + 80)
40    ((& phone::_ZTV5phone) + 136)
48    ((& phone::_ZTV5phone) + 80)

Class phone
   size=48 align=8
   base size=26 base align=8
phone (0x0x6fffe458ce0) 0
    vptridx=0 vptr=((& phone::_ZTV5phone) + 24)
  communicator (0x0x6fffe53c1c8) 0
      primary-for phone (0x0x6fffe458ce0)
      subvttidx=8
    hardware (0x0x6fffe2808a0) 32 virtual
        vptridx=40 vbaseoffset=-24 vptr=((& phone::_ZTV5phone) + 136)
  camera (0x0x6fffe53c230) 16
      subvttidx=24 vptridx=48 vptr=((& phone::_ZTV5phone) + 80)
    hardware (0x0x6fffe2808a0) alternative-path

  根据内存地址构建的对象内存结构如下(不同编译器实现不同,windows平台的cl编译器并没有深红色的部分(vs2015),这部分具体是什么,我不是很确定,又看到部分博客说是和虚基类的偏移,具体没有比较权威的资料,不做过多的解释,之后看到相关解释再补充):
C++继承类内存模型_第10张图片

  可以看到基类只保留了一份内存。

你可能感兴趣的:(c++)