zoukankan      html  css  js  c++  java
  • 派生类地址比基类地址少4(CDerived对象的起始地址存放的是虚表指针vptr,也就是子类的第一项内容。接下来的是基类的成员变量,接下来再是自身的成员变量)

    大家对虚表并不陌生,都知道每个含有虚函数的类对象都有1个虚指针,但是在现实使用中,却总是因为这而调试半天,才发现原来是虚指针惹的祸。我这几天在调试代码时候也中招了,我的问题是这样的,如下图,CTree是最底层基类(非虚类), CSamplerTree(虚类)派生自CTree,CMSamplerTree,CASamplerTree派生自CSamplerTree,  

                                                            

    CTree中包括两个成员变量,QList <CTree *> childList;树中有多少个孩子节点;CTree *parent;当前树节点的父亲节点,程序中我大量使用CTree *pTree指针指向CSamplerTree、CMSamplerTree、CASamplerTree ,从而达到统一处理的目的,从而使代码很简洁,复用性高。但是谁曾想到,程序一运行就会崩溃,通过调试发现,CSamplerTree、CMSamplerTree、CASamplerTree的指针当指向CTree的指针时,地址均加了4,为什么呢?为了加深理解,我做了一个简单的测试代码:

    1.  
      #include <stdio.h>class CBase {
    2.  
      public:
    3.  
      CBase() {}
    4.  
      void func()
    5.  
      {
    6.  
      printf("base ");
    7.  
      }
    8.  
      };
    9.  
      class CDerived : public CBase {
    10.  
      public:
    11.  
      CDerived() {}
    12.  
      virtual void func1()
    13.  
      {
    14.  
      printf("derived ");
    15.  
      }
    16.  
      };
    17.  
      void main()
    18.  
      {
    19.  
      CBase *pBase = new CDerived();
    20.  
      pBase->func();
    21.  
      CDerived *pDerived = (CDerived *)pBase;
    22.  
      printf("%d %d ", pDerived, pBase);
    23.  
      pDerived->func();
    24.  
      CBase *pBase1 = new CBase();
    25.  
      pBase1->func();
    26.  
      CDerived *pDerived1 = (CDerived *)pBase1;
    27.  
      printf("%d %d ", pDerived1, pBase1);
    28.  
      pDerived1->func();
    29.  
      }

    下面是输出的结果,从结果可以看出派生类指针指向基类指针,指针地址会加4,基类指针指向派生类时,指针地址会减4。

    base
    200672 200676
    derived
    base
    200740 200744
    Press any key to continue

    下面我们看看派生类对象和基类对象的内存是如何组织的,我们在上例的基础上引入2个变量,代码如下:

    1.  
      #include <stdio.h>class CBase {
    2.  
      public:
    3.  
      CBase() {}
    4.  
      void func()
    5.  
      {
    6.  
      printf("base ");
    7.  
      }
    8.  
      int a;
    9.  
      };
    10.  
      class CDerived : public CBase {
    11.  
      public:
    12.  
      CDerived() {}
    13.  
      virtual void func1()
    14.  
      {
    15.  
      printf("derived ");
    16.  
      }
    17.  
      int b;
    18.  
      };
    19.  
      void main()
    20.  
      {
    21.  
      CBase *pBase = new CDerived();
    22.  
      CDerived *pDerived = (CDerived *)pBase;
    23.  
      printf("%d %d ", pDerived, pBase);
    24.  
      printf("%d %d %d ", &pDerived->a, &pDerived->b, &pBase->a);
    25.  
      }
    26.  
       

    200672 200676
    200676 200680 200676
    Press any key to continue
    从输出结果我们可看出,CDerived对象的起始地址存放的是虚表指针vptr,接下来的是基类的成员变量,接下来再是自身的成员变量。

    https://blog.csdn.net/rabinsong/article/details/8923137

  • 相关阅读:
    搜索1011
    搜索1008(二分)
    贪心算法专题总结
    贪心算法1002
    c++笔记
    贪心算法1017
    贪心算法1008
    贪心算法1013
    Ubuntu中 sudo update与sudo upgrade的作用及区别
    requirejs 扩展,支持脚本资源预加载
  • 原文地址:https://www.cnblogs.com/findumars/p/9568613.html
Copyright © 2011-2022 走看看