首页 | 互联网 | IT动态 | IT培训 | Cisco | Windows | Linux | Java | .Net | Oracle | 软件测试 | C/C++ | 嵌入式开发 | 存储世界 | 服务器
网络设备 | IDC | 安全 | 求职招聘 | 数字网校 | 网页设计 | 平面设计 | 技术专题 | 电子书下载 | 教学视频 | 源码下载 | 搜索 | 博客 | 论坛
ASP | ASP.NET | JSP | PHP | AJAX | XML | Java script | HTML/CSS | 服务器类
各大城市软件开发培训、软件人才免费咨询热线:400-700-5807
 您现在的位置: 中国IT实验室 >> WEB开发 >> WEB开发 >> 正文
ATL布幔下的秘密之内部工作方式(1)
ChinaItLab  2004-12-29  保存本文    收藏本站


  介绍
  在本系列的教程中,我要讨论一些ATL的内部工作方式以及它所使用的技术。
  
  在讨论的开始,让我们先看看一个程序的内存分布。首先,编写一个简单的程序,它没有任何的数据成员,你可以看看它的内存结构。
  
  程序1.
  #include <iostream>
  using namespace std;
  
  class Class {
  };
  
  int main() {
  Class objClass;
  cout << "Size of object is = " << sizeof(objClass) << endl;
  cout << "Address of object is = " << &objClass << endl;
  return 0;
  }
  
  这个程序的输出为:
  
  Size of object is = 1
  Address of object is = 0012FF7C
  
  现在,如果我们向类中添加一些数据成员,那么这个类的大小就会是各个成员的大小之和。对于模板,也依然是这样:
  
  程序2.
  #include <iostream>
  using namespace std;
  
  template <typename T>
  class CPoint {
  public:
  T m_x;
  T m_y;
  };
  
  int main() {
  CPoint<int> objPoint;
  cout << "Size of object is = " << sizeof(objPoint) << endl;
  cout << "Address of object is = " << &objPoint << endl;
  return 0;
  }
  
  现在程序的输出为:
  
  Size of object is = 8
  Address of object is = 0012FF78
  
  那么,再向程序中添加继承。现在我们使Point3D类继承自Point类,然后来看看程序的内存结构:
  
  程序3.
  #include <iostream>
  using namespace std;
  
  template <typename T>
  class CPoint {
  public:
  T m_x;
  T m_y;
  };
  
  template <typename T>
  class CPoint3D : public CPoint<T> {
  public:
  T m_z;
  };
  
  int main() {
  CPoint<int> objPoint;
  cout << "Size of object Point is = " << sizeof(objPoint) << endl;
  cout << "Address of object Point is = " << &objPoint << endl;
  
  CPoint3D<int> objPoint3D;
  cout << "Size of object Point3D is = " << sizeof(objPoint3D) << endl;
  cout << "Address of object Point3D is = " << &objPoint3D << endl;
  
  return 0;
  }
  
  程序的输出为:
  
  Size of object Point is = 8
  Address of object Point is = 0012FF78
  Size of object Point3D is = 12
  Address of object Point3D is = 0012FF6C
  
  这一程序演示了派生类的内存结构,它表明派生类的对象所占据的内存为它本身的数据成员和它基类的成员之和。
  
  当虚函数加入到这个派对中的时候,一切就变得都有意思了。请看下面的程序:
  
  程序4.
  #include <iostream>
  using namespace std;
  
  class Class {
  public:
  virtual void fun() { cout << "Class::fun" << endl; }
  };
  
  int main() {
  Class objClass;
  cout << "Size of Class = " << sizeof(objClass) << endl;
  cout << "Address of Class = " << &objClass << endl;
  return 0;
  }
  
  程序的输出为:
  
  Size of Class = 4
  Address of Class = 0012FF7C
  
  并且,在我们添加了多于一个的虚函数之后,会变得更加有趣:
  
  程序5.
  #include <iostream>
  using namespace std;
  
  class Class {
  public:
  virtual void fun1() { cout << "Class::fun1" << endl; }
  virtual void fun2() { cout << "Class::fun2" << endl; }
  virtual void fun3() { cout << "Class::fun3" << endl; }
  };
  
  int main() {
  Class objClass;
  cout << "Size of Class = " << sizeof(objClass) << endl;
  cout << "Address of Class = " << &objClass << endl;
  return 0;
  }
  
  这个程序的输出和前一个程序一模一样,让我们再做一个实验来更好地弄懂这件事吧。
  
  程序6.
  #include <iostream>
  using namespace std;
  
  class CPoint {
  public:
  int m_ix;
  int m_iy;
  virtual ~CPoint() { } // 译注:原文此处有分号,我将其去掉,下皆同
  };
  
  int main() {
  CPoint objPoint;
  cout << "Size of Class = " << sizeof(objPoint) << endl;
  cout << "Address of Class = " << &objPoint << endl;
  return 0;
  }
  
  程序的输出为:
  
  Size of Class = 12
  Address of Class = 0012FF68
  
  这些程序的输出表明,当你向类中添加了虚函数之后,那么它的尺寸就会增加一个int的大小。在Visual C++中也就是增加4个字节。这就意味着这个类中有三个整数大小的位置,一个是x,一个是y,另一个是处理虚函数之用的虚函数表指针。首先,让我们来看看这个新的位置,也就是这个位于对象首部(或末尾)的虚函数表指针。要这么做的话,我们需要直接存取对象所占用的内存。我们可以使用神奇的指针技术,即用一个指向int的指针来存储一个对象的地址。
  
  程序7.
  #include <iostream>
  using namespace std;
  
  class CPoint {
  public:
  int m_ix;
  int m_iy;
  CPoint(const int p_ix = 0, const int p_iy = 0) :
  m_ix(p_ix), m_iy(p_iy) {
  }
  int getX() const {
  return m_ix;
  }
  int getY() const {
  return m_iy;
  }
  virtual ~CPoint() { }
  };
  
  int main() {
  CPoint objPoint(5, 10);
  
  int* pInt = (int*)&objPoint;
  *(pInt+0) = 100; // 企图改变x的值
  *(pInt+1) = 200; // 企图改变y的值
  
  cout << "X = " << objPoint.getX() << endl;
  cout << "Y = " << objPoint.getY() << endl;
  
  return 0;
  }
  
  这个程序中最重要的东西是:
  
  int* pInt = (int*)&objPoint;
  *(pInt+0) = 100; // 企图改变x的值
  *(pInt+1) = 200; // 企图改变y的值
  
  其中,我们在把对象的地址存入一个整型指针之后,就可以把这个对象看作一个整型的指针了。程序的输出为:
  
  X = 200
  Y = 10
  
  当然,这并不是我们想要的结果,它表明200存储在了m_ix数据成员的位置。这就意味着m_ix,也就是第一个成员变量,是起始于内存中第二个位置的,而不是第一个。换句话说,第一个成员是虚函数表指针,其它的才是对象的数据成员。那么,只需要修改以下的两行:
  
  int* pInt = (int*)&objPoint;
  *(pInt+1) = 100; // 企图改变x的值
  *(pInt+2) = 200; // 企图改变y的值
  
  这样我们就会获得想要的结果了,以下为完整程序:
  
  程序8.
  #include <iostream>
  using namespace std;
  
  class CPoint {
  public:
  int m_ix;
  int m_iy;
  CPoint(const int p_ix = 0, const int p_iy = 0) :
  m_ix(p_ix), m_iy(p_iy) {
  }
  int getX() const {
  return m_ix;
  }
  int getY() const {
  return m_iy;
  }
  virtual ~CPoint() { }
  };
  
  int main() {
  CPoint objPoint(5, 10);
  
  int* pInt = (int*)&objPoint;
  *(pInt+1) = 100; // 企图改变x的值
  *(pInt+2) = 200; // 企图改变y的值
  
  cout << "X = " << objPoint.getX() << endl;
  cout << "Y = " << objPoint.getY() << endl;
  
  return 0;
  }
  
  并且,程序的输出为:
  
  X = 100
  Y = 200
  
  下图清楚地示范了当我们向类中添加了虚函数之后,虚函数表指针就会被添加在内存结构中的第一个位置。
   
  现在问题出现了:虚函数表指针中到底存储了什么?那么看看下面的程序:
  
  程序9.
  #include <iostream>
  using namespace std;
  
  class Class {
  virtual void fun() { cout << "Class::fun" << endl; }
  };
  
  int main() {
  Class objClass;
  
  cout << "Address of virtual pointer " << (int*)(&objClass+0) << endl;
  cout << "Value at virtual pointer " << (int*)*(int*)(&objClass+0) << endl;
  return 0;
  }
  
  程序的输出为:
  
  Address of virtual pointer 0012FF7C
  Value at virtual pointer 0046C060
  
  虚函表数
中国IT教育热线咨询
相关文章
Flash+PHP+Mysql简单留言本制作实例教程
基础知识:Java Web三层架构的配置详解
使用AJAX技术构建更优秀的Web应用程序
ASP应用程序设计的Web状态管理分析
Ajax驱动的Web站点
最新文章
·Ajax光环背后的隐患
·Windows操作系统下JSP程序开发环
·如何在Java程序中实现FTP的上传下
·Java应用:编写高级JavaScript应
·初学者学习java第一步——JDK环境
 文章评论

 精彩友情推荐
·Asp源码 PHP源码
·CGI源码 JSP源码
·建站书籍教程
·服务器软件 .net源码
·建站工具软件
·IDC资讯大全
·机房品质万里行
·IDC托管必备知识
·全国IDC报价
·网站推广优化
ASP.NET ASP PHP JSP
·ASP.NET开发中的八个最佳实践09-21
·ASP.NET开发中的验证码技术09-18
·控件开发asp.net处理标签间内容09-18
·程序员成为成为编程高手的二十二条军规09-18
·VS 2005和ASP.NET 2.0中处理CSS样式表09-17
·如何有效监控.NET应用程序09-16
·浅析ASP.NET 2.0 Client Callback09-16
·探讨ASP.NETMVC框架内置AJAX支持编程技术09-15
·ASP.NET2.0的URL映射的实现方法09-13
·Java\.net\PHP比较 程序员眼中的.Net世界09-12
·asp.net中实现观察者设计模式09-12
·谈JSP与XML的交互09-01
·ASP连接11种数据库语法总结09-01
·如何利用ASP实现邮箱访问09-01
·ASP随机数的应用技术09-01
·定时使用DWRUtil.addRow生成表格08-27
·ASP申请单动态添加实现方法及代码08-27
·关于ASP中脚本执行顺序的讲解08-25
·ASP程序实现网页伪静态页源代码08-25
·ASP如何调用webservice08-22
·ASP实例:读取xml文件的程序08-14
·Asp组件检测函数08-11
·Linux系统下让PHP提高性能的工具APC05-06
·一个完整、安全的PHP用户登录系统11-14
·Apache+PHP+MySQL建立数据库驱动的动态网站08-24
·用SSH与PHP相连接 确保数据传输的安全性08-23
·PHP5手动最简安装方法08-03
·PHP程序加速探索之服务器负载测试07-11
·完全讲解PHP+MySQL的分页显示示例分析05-30
·用Suhosin加强PHP脚本语言安全性05-26
·初学入门 PHP 和 MySQL05-17
·传奇的诞生 PHP三位创始人简介05-10
·大型系统上PHP令人不爽的九大原因05-10
·JSTL中fn表达式的使用说明09-18
·JSP Web框架研究:Struts09-16
·JSF在GlassFish管理控制台中的应用09-12
·介绍JSP程序动态网站环境搭建的详细步骤09-12
·Jsp页面中文参数传递get和post方法分析09-12
·Java\.net\PHP比较 程序员眼中的.Net世界09-11
·JavaScript最常用的55个经典技巧09-08
·Windows操作系统下JSP程序开发环境配置09-03
·JSF点滴积累--权限验证09-03
·小小分页帮助程序08-29
·经验分享全过程JSP程序员完全蜕变手册08-27
  培训中心
人才交流中心 技术交流中心
  ITLab技术交流平台: