的笔记

随时随地编辑

虚函数与对象布局

类布局

代码 类布局
    class Base1 {
            public:
            void f0() {}
            virtual void f1() {}
            virtual void f2() {}
            virtual void f3() {}
            int int_in_b1;
            };
            class Middle2 : public Base1 {
            public:
            virtual void g1() {}
            virtual void g2() {}
            virtual void g3() {}
            int int_in_b2;
            };
            class Top3 : public Middle2 {
            public:
            virtual void h1() {}
            virtual void h2() {}
            virtual void h3() {}
            int int_in_b3;
            virtual void f1() {}
            };
            
    -----------------------------------
            class Base1 size(8):
            +---
            0 | {vfptr}
            4 | int_in_b1
            +---
            Base1::$vftable@:
            | &Base1_meta
            |  0
            0 | &Base1::f1
            1 | &Base1::f2
            2 | &Base1::f3
            -----------------------------------
            class Middle2 size(12):
            +---
            | +--- (base class Base1)
            0 | | {vfptr}
            4 | | int_in_b1
            | +---
            8 | int_in_b2
            +---
            Middle2::$vftable@:
            | &Middle2_meta
            |  0
            0 | &Base1::f1
            1 | &Base1::f2
            2 | &Base1::f3
            3 | &Middle2::g1
            4 | &Middle2::g2
            5 | &Middle2::g3
            -----------------------------------
            class Top3 size(16):
            +---
            | +--- (base class Middle2)
            | | +--- (base class Base1)
            0 | | | {vfptr}
            4 | | | int_in_b1
            | | +---
            8 | | int_in_b2
            | +---
            12 | int_in_b3
            +---
            Top3::$vftable@:
            | &Top3_meta
            |  0
            0 | &Top3::f1
            1 | &Base1::f2
            2 | &Base1::f3
            3 | &Middle2::g1
            4 | &Middle2::g2
            5 | &Middle2::g3
            6 | &Top3::h1
            7 | &Top3::h2
            8 | &Top3::h3
            -----------------------------------
            
>

输出虚表

Visual C++在cl编译时加上命令行"/d1 reportAllClassLayout"或"/d1 reportSingleClassLayoutXXX",XXX换成类名,会输出类的对象布局。
命令行: cl c:\foo.cpp /c /d1 reportAllClassLayout
IDE:在设置里C++命令里加上这行命令。

参考

How can one inspect a vtable in Visual C++?
Diagnosing Hidden ODR Violations in Visual C++ (and fixing LNK2022)

结论

  • 对象的开始4个字节始终是虚表的地址(如果有)。这个结论在查对象被破坏、运行时崩溃等bug时很重要。
  • 类只有一个虚表。基类的虚函数和自身的都会合并到一个地址里去。
  • 如果继承类重载了某个虚函数,其实在虚表里是会将基类被重载的虚函数从虚表里‘抹掉’,所以你要访问基类里被重载了的虚函数,只能用“基类::函数名”访问。例如上面的‘Top3::f1 ’。
  • 虚函数不会增加对象体积吧,以前怎么会有这个观念...

posted on 2014-07-04 16:09 的笔记 阅读(381) 评论(0)  编辑 收藏 引用 所属分类: C++


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理