37 C++ 对象模型

1 class 与 struct

  • class 是一种特殊的 struct

    • 在内存中,class 依旧可以看作变量的集合
    • classstruct 遵循相同的内存对齐规则
    • class 中的成员函数(是函数,只可能存放在代码段中)成员变量(是数据,存放于三个数据区中:栈,堆,全局数据区)是分开存放的
      • 每个对象有独立的成员变量
      • 所有对象共享类中的成员函数
  • 问题:sizeof(A) = ?,sizeof(B) = ?

    • sizeof(A) = 20
    • sizeof(B) = 20
    class A 
    {
        int i;
        int j;
        char c;
        double d;
    };
    
    struct B
    {
        int i;
        int j;
        char c;
        double d;
    };
    
  • 示例1:对象内存布局

    • Demo

      #include <iostream>
      #include <string>
      
      using namespace std;
      
      class A
      {
          int i;
          int j;
          char c;
          double d;
      public:
          void print()
          {
              cout << "i = " << i << ", "
                   << "j = " << j << ", "
                   << "c = " << c << ", "
                   << "d = " << d << endl;
          }
      };
      
      struct B
      {
          int i;
          int j;
          char c;
          double d;
      };
      
      int main()
      {
          A a;
          
          cout << "sizeof(A) = " << sizeof(A) << endl;    // 20 bytes
          cout << "sizeof(a) = " << sizeof(a) << endl;    // 20 bytes
          cout << "sizeof(B) = " << sizeof(B) << endl;    // 20 bytes
          
          a.print();
          
          //强制类型转换:重新解释这段内存
          B* p = reinterpret_cast<B*>(&a);
          
          p->i = 1;
          p->j = 2;
          p->c = 'c';
          p->d = 3;
          
          a.print();
          
          p->i = 100;
          p->j = 200;
          p->c = 'C';
          p->d = 3.14;
          
          a.print();
          
          return 0;
      }
      
    • 编译运行

      sizeof(A) = 20
      sizeof(a) = 20
      sizeof(B) = 20
      i = 134515232, j = -1075608584, c = ?, d = 4.85991e-270
      i = 1, j = 2, c = c, d = 3
      i = 100, j = 200, c = C, d = 3.14
      

2 C++ 对象模型分析

  • 运行时的对象退化为结构体的形式

    • 所有成员变量在内存中依次分布
    • 成员变量间可能存在内存空隙
    • 可以通过内存地址直接访问成员变量
    • 访问权限关键字在运行时失效
  • 类的对象调用成员函数原理

    • 类的成员函数位于代码段
    • 调用成员函数时对象地址作为参数隐式传递
    • 成员函数通过对象地址访问成员变量
    • C++ 语法规则隐藏了对象地址的传递过程
  • 示例2:对象本质分析

    • Demo1:C++ 类对象调用成员函数

      #include <iostream>
      #include <string>
      
      using namespace std;
      
      class Demo
      {
          int mi;
          int mj;
      public:
          Demo(int i, int j)
          {
              mi = i;
              mj = j;
          }
          
          int getI()
          {
              return mi;
          }
          
          int getJ()
          {
              return mj;
          }
          
          int add(int value)
          {
              return mi + mj + value;
          }
      };
      
      int main()
      {
          Demo d(1, 2);
          
          cout << "sizeof(d) = " << sizeof(d) << endl;  //8
          cout << "d.getI() = " << d.getI() << endl;
          cout << "d.getJ() = " << d.getJ() << endl;
          cout << "d.add(3) = " << d.add(3) << endl;
          
          return 0;
      }
      
    • Demo2:C 语言实现上述过程

      //test.c
      #include <stdio.h>
      #include "object.h"
      
      int main()
      {
          Demo* d = Demo_Create(1, 2);             // Demo* d = new Demo(1, 2);
          
          printf("d.mi = %d
      ", Demo_GetI(d));     // d->getI();
          printf("d.mj = %d
      ", Demo_GetJ(d));     // d->getJ();
          printf("Add(3) = %d
      ", Demo_Add(d, 3));    // d->add(3);
          
          // d->mi = 100;  //error
          
          Demo_Free(d);
          
          return 0;
      }
      
      
      //object.h
      #ifndef _OBJECT_H_
      #define _OBJECT_H_
      
      typedef void Demo;
      
      Demo* Demo_Create(int i, int j);
      int Demo_GetI(Demo* pThis);
      int Demo_GetJ(Demo* pThis);
      int Demo_Add(Demo* pThis, int value);
      void Demo_Free(Demo* pThis);
      
      #endif
      
      
      //object.c
      #include "object.h"
      #include "malloc.h"
      
      struct ClassDemo
      {
          int mi;
          int mj;
      };
      
      Demo* Demo_Create(int i, int j)
      {
          struct ClassDemo* ret = (struct ClassDemo*)malloc(sizeof(struct ClassDemo));
          
          if( ret != NULL )
          {
              ret->mi = i;
              ret->mj = j;
          }
          
          return ret;
      }
      
      int Demo_GetI(Demo* pThis)
      {
           struct ClassDemo* obj = (struct ClassDemo*)pThis;
           
           return obj->mi;
      }
      
      int Demo_GetJ(Demo* pThis)
      {
          struct ClassDemo* obj = (struct ClassDemo*)pThis;
           
          return obj->mj;
      }
      
      int Demo_Add(Demo* pThis, int value)
      {
          struct ClassDemo* obj = (struct ClassDemo*)pThis;
           
          return obj->mi + obj->mj + value;
      }
      
      void Demo_Free(Demo* pThis)
      {
          free(pThis);
      }
      
    • 编译运行

      d.mi = 1
      d.mi = 2
      Add(3) = 6
      

3 继承对象模型

  • 在 C++ 编译器的内部,类可以理解为结构体

  • 子类是由父类成员叠加子类新成员得到的

    class Derived : public Demo
    {
        int  mk;
    }
    
  • 示例3:继承对象模型

    • Demo

      #include <iostream>
      #include <string>
      
      using namespace std;
      
      class Demo
      {
      protected:
          int mi;
          int mj;
      public:
          void print()
          {
              cout << "mi = " << mi << ", "
                   << "mj = " << mj << endl;
          }
      };
      
      class Derived : public Demo
      {
          int mk;
      public:
          Derived(int i, int j, int k)
          {
              mi = i;
              mj = j;
              mk = k;
          }
          
          void print()
          {
              cout << "mi = " << mi << ", "
                   << "mj = " << mj << ", "
                   << "mk = " << mk << endl;
          }
      };
      
      struct Test
      {
          int mi;
          int mj;
          int mk;
      };
      
      int main()
      {
          cout << "sizeof(Demo) = " << sizeof(Demo) << endl;         
          cout << "sizeof(Derived) = " << sizeof(Derived) << endl;  
          
          Derived d(1, 2, 3);
          Test* p = reinterpret_cast<Test*>(&d);
          
          cout << "Before changing ..." << endl;
          
          d.print();
          
          p->mi = 10;
          p->mj = 20;
          p->mk = 30;
          
          cout << "After changing ..." << endl;
          
          d.print();
          
          return 0;
      }
      
  • 编译运行:说明结构体 Test 和类 Derived 的内存分布相同

      sizeof(Demo) = 8
      sizeof(Derived) = 12
      Before changing ...
      mi = 1, mj = 2, mk = 3
      After changing ...
      mi = 10, mj = 20, mk = 30
    

4 多态对象模型

  • 多态的概念:相同的行为方式,不同的行为结果。由具体的编程语言实现,在 C++ 中由虚函数实现

  • C++ 多态的实现原理

    • 当类中声明虚函数时,编译器会在类中生成一个虚函数表(VTABLE)
    • 虚函数表是一个存储成员(虚)函数地址的数据结构
    • 虚函数表是由编译器自动生成维护的
    • virtual 成员函数会被编译器放入虚函数表中
    • 存在虚函数时,每个对象中都有一个指向虚函数表的指针:虚函数表指针(VPTR)
  • 示例4:多态对象模型

    • Demo

      #include <iostream>
      #include <string>
      
      using namespace std;
      
      class Demo
      {
      protected:
          int mi;
          int mj;
      public:
          virtual void print()
          {
              cout << "mi = " << mi << ", "
                   << "mj = " << mj << endl;
          }
      };
      
      class Derived : public Demo
      {
          int mk;
      public:
          Derived(int i, int j, int k)
          {
              mi = i;
              mj = j;
              mk = k;
          }
          
          void print()
          {
              cout << "mi = " << mi << ", "
                   << "mj = " << mj << ", "
                   << "mk = " << mk << endl;
          }
      };
      
      struct Test
      {
          void* p;  //模拟虚函数表指针,放在最开始的四个字节处
          int mi;
          int mj;
          int mk;
      };
      
      int main()
      {
          cout << "sizeof(Demo) = " << sizeof(Demo) << endl;         
          cout << "sizeof(Derived) = " << sizeof(Derived) << endl;  
          
          Derived d(1, 2, 3);
          Test* p = reinterpret_cast<Test*>(&d);
          
          cout << "Before changing ..." << endl;
          
          d.print();
          
          p->mi = 10;
          p->mj = 20;
          p->mk = 30;
          
          cout << "After changing ..." << endl;
          
          d.print();
          
          return 0;
      }
      
    • 编译运行

      sizeof(Demo) = 12
      sizeof(Derived) = 16
      Before changing ...
      mi = 1, mj = 2, mk = 3
      After changing ...
      mi = 10, mj = 20, mk = 30
      
  • 示例:多态本质分析

    • Demo

      //test.c
      #include "stdio.h"
      #include "51-2.h"
      
      void run(Demo* p, int v)
      {
          int r = Demo_Add(p, v);
          
          printf("r = %d
      ", r);
      }
      
      int main()
      {
          Demo* pb = Demo_Create(1, 2);
          Derived* pd = Derived_Create(1, 22, 333);
          
          printf("pb->add(3) = %d
      ", Demo_Add(pb, 3));
          printf("pd->add(3) = %d
      ", Derived_Add(pd, 3));
          
          run(pb, 3);
          run(pd, 3);
          
          Demo_Free(pb);
          Demo_Free(pd);
          
          return 0;
      }
      
      
      //
      #ifndef _51_2_H_
      #define _51_2_H_
      
      typedef void Demo;
      typedef void Derived;
      
      Demo* Demo_Create(int i, int j);
      int Demo_GetI(Demo* pThis);
      int Demo_GetJ(Demo* pThis);
      int Demo_Add(Demo* pThis, int value);
      void Demo_Free(Demo* pThis);
      
      Derived* Derived_Create(int i, int j, int k);
      int Derived_GetK(Derived* pThis);
      int Derived_Add(Derived* pThis, int value);
      
      #endif
      
      
      //
      #include "51-2.h"
      #include "malloc.h"
      
      static int Demo_Virtual_Add(Demo* pThis, int value);
      static int Derived_Virtual_Add(Demo* pThis, int value);
      
      struct VTable     // 2. 定义虚函数表数据结构
      {
          int (*pAdd)(void*, int);   // 3. 虚函数表里面存储什么???
      };
      
      struct ClassDemo
      {
          struct VTable* vptr;     // 1. 定义虚函数表指针  ==》 虚函数表指针类型???
          int mi;
          int mj;
      };
      
      struct ClassDerived
      {
          struct ClassDemo d;
          int mk;
      };
      
      static struct VTable g_Demo_vtbl = 
      {
          Demo_Virtual_Add
      };
      
      static struct VTable g_Derived_vtbl = 
      {
          Derived_Virtual_Add
      };
      
      Demo* Demo_Create(int i, int j)
      {
          struct ClassDemo* ret = (struct ClassDemo*)malloc(sizeof(struct ClassDemo)); 
      
          if( ret != NULL )
          {
              ret->vptr = &g_Demo_vtbl;   // 4. 关联对象和虚函数表
              ret->mi = i;
              ret->mj = j;
          }
          
          return ret;
      }
      
      int Demo_GetI(Demo* pThis)
      {
           struct ClassDemo* obj = (struct ClassDemo*)pThis;    
      
           return obj->mi;
      }
      
      int Demo_GetJ(Demo* pThis)
      {
          struct ClassDemo* obj = (struct ClassDemo*)pThis;
      
          return obj->mj;
      }
      
      // 6. 定义虚函数表中指针所指向的具体函数
      static int Demo_Virtual_Add(Demo* pThis, int value)
      {
          struct ClassDemo* obj = (struct ClassDemo*)pThis;
          
          return obj->mi + obj->mj + value;
      }
      
      
      // 5. 分析具体的虚函数!!!!
      int Demo_Add(Demo* pThis, int value)
      {
      
          struct ClassDemo* obj = (struct ClassDemo*)pThis;
      
          return obj->vptr->pAdd(pThis, value);
      }
      
      void Demo_Free(Demo* pThis)
      {
          free(pThis);
      }
      
      Derived* Derived_Create(int i, int j, int k)
      {
          struct ClassDerived* ret = (struct ClassDerived*)malloc(sizeof(struct ClassDerived));
          
          if( ret != NULL )
          {
              ret->d.vptr = &g_Derived_vtbl;
              ret->d.mi = i;
              ret->d.mj = j;
              ret->mk = k;
          }
          
          return ret;
      }
      
      int Derived_GetK(Derived* pThis)
      {
          struct ClassDerived* obj = (struct ClassDerived*)pThis;
          
          return obj->mk;
      }
      
      static int Derived_Virtual_Add(Demo* pThis, int value)
      {
          struct ClassDerived* obj = (struct ClassDerived*)pThis; 
      
          return obj->mk + value;
      }
      
      int Derived_Add(Derived* pThis, int value)
      {   
          struct ClassDerived* obj = (struct ClassDerived*)pThis;
          
          return obj->d.vptr->pAdd(pThis, value);
      }
      
    • 编译运行

原文地址:https://www.cnblogs.com/bky-hbq/p/13903923.html