您现在的位置: 中国男护士网 >> 考试频道 >> 计算机等级 >> 二级辅导 >> C十十 >> 辅导 >> 正文    
  C++虚函数;虚析构函数;类的存储空间 【注册男护士专用博客】          

C++虚函数;虚析构函数;类的存储空间

www.nanhushi.com     佚名   不详 

  1、类的存储空间
  在INTEL 32 CPU,VC6环境下,空类的一个实例占一个字节;
  虚拟函数表指针占4个字节。
  2、虚函数的实现过程
  [网上很多讲解, 本文有源代码和部分汇编代码]
  3、虚拟析构函数
  无论基类的析构函数是否为虚析构函数. 基类的析构函数总是会被自动调用的;
  但是, 如果用基类指针去操作一个了派生类对象,
  那么在delete这个基类指针时,派生类的析构函数将不会被调用.
  4. 补充: 一个C++类本身,在内存里是有信息的, 除了上面 虚函数表, 还有静态成员变量。
  VC6下的代码:
  // Test.cpp : Defines the entry point for the console application.
  //
  #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
  #include <stdio.h>
  class Base;
  class Derived;
  void GFunction(void);
  int main(int argc, char* argv[])
  {
  GFunction();
  char a = 127;
  a+=1;
  printf("new a = %d\n", a);
  getchar();
  return 0;
  }
  class Base
  {
  public:
  Base::Base()
  {
  };
  virtual Base::~Base()
  {
  printf("Base deconstruct\n");
  };
  virtual void Fun()
  {
  };
  int a ;
  };
  class Derived : public Base
  {
  public:
  Derived::Derived()
  {
  };
  virtual Derived::~Derived()
  {
  printf("Derived deconstruct\n");
  };
  virtual void Fun()
  {
  };
  };
  void GFunction(void)
  {
  printf("Class Base Sizeof =%d \n", sizeof(Base));
  printf("Class Derived Sizeof =%d \n\n", sizeof(Derived));
  Base* pA = (Base*)new Derived;
  pA->Fun(); // 虚函数调用
  delete pA;
  }
  pA->Fun()的汇编代码如下:
  59: pA->Fun();
  0040D75C mov edx,dword ptr [ebp-10h] // edx为pA
  0040D75F mov eax,dword ptr [edx] // eax为pA对象的虚表指针pVTable
  0040D761 mov esi,esp
  0040D763 mov ecx,dword ptr [ebp-10h] // this指针存入ecx
  0040D766 call dword ptr [eax+4] // 函数地址:虚表指针+4, 就是虚表中第二项
  0040D769 cmp esi,esp
  0040D76B call __chkesp (00401b20)
  1. 如果成员函数不是虚函数,那么编译的时候,就直接指定了调用函数的入口;
  2. 如果是虚函数,那么编译时不直接指定函数入口,而是先在对象的内存空间里取一个值(这个值就是虚函数表的地址,放在对象内存空间的最前面4个字节里)。汇编代码中会有取值的过程;
  3. 虚函数表中按顺序存放着虚函数在地址空间中的地址:的第一个DWORD存储的就是第一个虚函数的地址,第二个DWORD存储的就是第二个虚函数的地址;
  3. 编译器在编译过程中已经知道你调的那个函数在虚函数表中的序号。汇编代码中会有体现;
  4. 在运行时,就能正确找到调用函数的地址,并调用它.
  析构函数的一点补充:
  在一个项目中,如果有N层派生类,编译器总是保证所有基类的析构函数都被依次调用,但问题是,究竟从那层开始调用呢?对于非虚析构函数,显然是在编译期间就直接确定的,对虚析构函数,在运行时,才能确定是从哪一层开始往下层调用(基类)。
  事实上,和一般虚函数一样,运行时,才确定要调用的析构函数,不过有些不同的是,析构函数执行完后,下一条指令就是基类析构函数的CALL指令,一直到最上层为止。
  下面是一段debug下的反汇编,其中Base派生自BaseBase.可以看到~Base调用后,会自动调用~BaseBase
  virtual Base::~Base() // 基类析构函数
  {
  00401740 push ebp
  00401741 mov ebp,esp
  00401743 sub esp,0CCh
  00401749 push ebx
  0040174A push esi
  0040174B push edi
  0040174C push ecx
  0040174D lea edi,[ebp-0CCh]
  00401753 mov ecx,33h
  00401758 mov eax,0CCCCCCCCh
  0040175D rep stos dword ptr es:[edi]
  0040175F pop ecx
  00401760 mov dword ptr [ebp-8],ecx
  00401763 mov eax,dword ptr [this]
  00401766 mov dword ptr [eax],offset Base::`vftable' (44533Ch)
  printf("Base deconstruct\n");
  0040176C push offset string "Base deconstruct\n" (445344h)
  00401771 call printf (405760h)
  00401776 add esp,4
  };
  00401779 mov ecx,dword ptr [this]
  0040177C call BaseBase::~BaseBase (4017A0h) // 上层基类也紧跟着调用了

 

文章录入:杜斌    责任编辑:杜斌 
  • 上一篇文章:

  • 下一篇文章:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
     

    联 系 信 息
    QQ:88236621
    电话:15853773350
    E-Mail:malenurse@163.com
    免费发布招聘信息
    做中国最专业男护士门户网站
    最 新 热 门
    最 新 推 荐
    相 关 文 章
    没有相关文章
    专 题 栏 目

      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)                            【进男护士社区逛逛】
    姓 名:
    * 游客填写  ·注册用户 ·忘记密码
    主 页:

    评 分:
    1分 2分 3分 4分 5分
    评论内容:
  • 请遵守《互联网电子公告服务管理规定》及中华人民共和国其他各项有关法律法规。
  • 严禁发表危害国家安全、损害国家利益、破坏民族团结、破坏国家宗教政策、破坏社会稳定、侮辱、诽谤、教唆、淫秽等内容的评论 。
  • 用户需对自己在使用本站服务过程中的行为承担法律责任(直接或间接导致的)。
  • 本站管理员有权保留或删除评论内容。
  • 评论内容只代表网友个人观点,与本网站立场无关。