• C++对象模型


    读 C++对象模型 总结 

    1. 类对象

    内存结构:数据成员按声明顺序排列

     1 class B {
     2 public:
     3    int bm1;
     4 protected:
     5    int bm2;
     6 private:
     7    int bm3;
     8    static int bsm;
     9    void bf();
    10    static void bsf();
    11    typedef void* bpv;
    12    struct N { };
    13 };

    2. 单继承

    内存结构:先基类,后自己

    1 class C {
    2    int c1;
    3    void cf();
    4 };
    1 class D : C {
    2    int d1;
    3    void df();
    4 };

    3. 多重继承

    内存结构:先基类(基类按从左往右的顺序排列),后自己

    1 class C {
    2    int c1;
    3    void cf();
    4 };
    1 class E {
    2    int e1;
    3    void ef();
    4 };
    1 class F : C, E {
    2    int f1;
    3    void ff();
    4 };

    4. 虚继承

    内存结构:引入vbptr,先自己,后基类

    1 class C {
    2    int c1;
    3    void cf();
    4 };
    1 class G : virtual C {
    2    int g1;
    3    void gf();
    4 };

    注:

    在VC++ 中,对每个虚继承自基类的实例,将增加一个隐藏的 vbptr(虚基类表指针)成员变量,从而达到间接计算虚基类位置的目的。该变量指向一个全类共享的偏移量表,表中项目记录了对于该类而言,vbptr 与类之间的偏移量。 

    GdGvbptrG(In G, the displacement of G’s virtual base pointer to G)意思是:在G中,G对象的指针与G的虚基类表指针之间的偏移量,在此可见为0,因为G对象内存布局第一项就是虚基类表指针; GdGvbptrC(In G, the displacement of G’s virtual base pointer to C)意思是:在G中,C对象的指针与G的虚基类表指针之间的偏移量,在此可见为8。

    5. 菱形继承

    内存结构:先父类,然后自己,最后基类

    1 class C {
    2    int c1;
    3    void cf();
    4 };
    1 class G : virtual C {
    2    int g1;
    3    void gf();
    4 };
    1 class H : virtual C {
    2    int h1;
    3    void hf();
    4 };
    1 class I : G, H {
    2    int i1;
    3    void _if();
    4 };

    6. 虚函数

    内存结构:引入vfptr

    1  P {
    2    int p1;
    3    void pf();           // new
    4    virtual void pvf();  // new
    5 };

    注:

     一个vfptr被加入到类中,该vfptr指向类的虚函数表(vftable)。类中每个虚函数在该类的虚函数表中都占据一项。每项保存一个对于该类适用的虚函数的地址。因此,调用虚函数的过程如下:取得实例的vfptr;通过vfptr得到虚函数表的一项;通过虚函数表该项的函数地址间接调用虚函数。 也就是说,在普通函数调用的参数传递、调用、返回指令开销外,虚函数调用还需要额外的开销。

    7. 覆盖成员函数

    内存结构:引入vfptr,先基类,后自己

    1  P {
    2    int p1;
    3    void pf();          // new
    4    virtual void pvf(); // new
    5 };
    1  Q : P {
    2    int q1;
    3    void pf();          // overrides P::pf
    4    void qf();          // new
    5    void pvf();         // overrides P::pvf
    6    virtual void qvf(); // new
    7 };

    注:

    覆盖是静态(根据成员函数的静态类型在编译时决定)还是动态(通过对象指针在运行时动态决定),依赖于成员函数是否被声明为 “ 虚函数 ” 。

    对于非虚函数来说,调用哪个成员函数是在编译时,根据 “ -> ” 操作符左边指针表达式的类型静态决定的。特别地,即使theP指向Q的实例,theP->pf()调用的仍然是P::pf(),因为theP被声明为 P* 。

    对于虚函数来说,调用哪个成员函数在运行时决定。不管 “ -> ” 操作符左边的指针表达式的类型如何,调用的虚函数都是由指针实际指向的实例类型所决定 。比如,尽管theP的类型是 P* ,当theP指向Q的实例时,调用的是Q::pvf()。

    8. 多重继承下的虚函数

    内存结构:引入vfptr,先基类,后自己

    1 class P {
    2    int p1;
    3    void pf();          // new
    4    virtual void pvf(); // new
    5 };
    1 class R {
    2    int r1;
    3    virtual void pvf(); // new
    4    virtual void rvf(); // new
    5 };
    1 class S : P, R {
    2    int s1;
    3    void pvf(); // overrides P::pvf and R::pvf
    4    void rvf(); // overrides R::rvf
    5    void svf(); // new
    6 };

    9. 虚继承下的虚函数

    内存结构:引入vfptr,引入vbptr,先自己,后基类

    1  class P {
    2     int p1;
    3     void pf();          // new
    4     virtual void pvf(); // new
    5  };
     1  class T : virtual P {
     2    int t1;
     3    void pvf();         // overrides P::pvf
     4    virtual void tvf(); // new
     5 };
     6 
     7 void T::pvf() {
     8    ++p1;              // ((P*)this)->p1++; // vbtable lookup!
     9    ++t1;              // this->t1++;
    10 }

    内存结构:引入vfptr,引入vbptr,先基类,后自己

    1  class U : T {
    2    int u1;
    3 };

  • 相关阅读:
    redis实现高并发下的抢购/秒杀功能
    redis分布式锁的实现(setNx命令和Lua脚本)
    【JAVA代码审计】——1、Spring框架知识篇
    使用edjpgcom工具制作一句话图片木马
    史上最强内网渗透知识点总结
    2018年云上挖矿分析报告
    Solidity 安全:已知攻击方法和常见防御模式综合列表
    【PHP渗透技巧拓展】————3、LFI、RFI、PHP封装协议安全问题学习
    【PHP渗透技巧拓展】————2、利用 Gopher 协议拓展攻击面
    【RPO技巧拓展】————5、RPO攻击初探
  • 原文地址:https://www.cnblogs.com/luzhiyuan/p/3945610.html
Copyright © 2020-2023  润新知