注册通行证 用户名 密码
  • 文章投稿
  • 博客
  • 论坛
  • 设为首页
  • 加入收藏
jztop.com网络技术
  • 首页
  • | iT新闻
  • | 操作系统
  • | 组网建网
  • | 网络安全
  • | 程序开发
  • | 办公一族
  • | 工具软件
  • | 网页制作
  • | 多媒体制作
  • | 网吧技术
  • | 服务器
  • | 专题教程
Vista | 软件评测 | 系统备份 | 优化 | 进程 | 聊天 | 病毒 | Linux | 黑客 | 防火墙 | 数据库 | Web开发 | Java | Word | 游戏 | 32位开发 | 移动开发
当前位置:首页 > 程序开发 > 32位开发 > C/C++ > 内容正文

C++对象计数

发布时间:2006-03-10 23:21:39 来源:友佳学院 网友评论 0 条

文本关键字:程序设计/C++/技巧

 

  本文目的是实现一个实用的对C++类计数的类,同时在实现过程中指出一些容易为人忽视的C++知识。
  要实现一个类的对象(实例)计数,即程序运行中此类有多少个对象存在,最容易的实现方法是使用静态数据成员。如下:

class Widget {public:    Widget() { ++count; }    Widget(const Widget&) { ++count; }    ~Widget() { --count; }    static size_t howMany()    { return count; }private:    static size_t count;};      //cpp文件中size_t Widget::count = 0;      
注意构造函数也要增加计数,这一点很多人容易忘记。
  但是如果程序中有多个需要实例计数的类,则在每个类中加入上面代码未免繁琐、易错。这种情况下,最好是实现一个通用计数类。它应该具备一下特点:
  • 易于使用:任何需要计数的类(以下简称客户类)只要添加少数代码即可使用;
  • 有效率:不增加客户类大小,对客户类性能没有影响;
  • 健壮:客户类使用时,不容易误用。
  • 下面我们将逐步实现并完善这个通用的计数类。

    class Counter {  public:              Counter() { ++count; }    Counter(const Counter&) { ++count; }    ~Counter() { --count; }    static size_t howMany()        { return count; }private:    static size_t count;};// This still goes in an implementation filesize_t Counter::count = 0;      
    上面这个Counter类能否正确完成计数呢?例如:Widget类利用它来进行实例计数:
    // embed a Counter to count objectsclass Widget {public:    .....  // all the usual public           // Widget stuff    static size_t howMany()    { return Counter::howMany(); }private:    .....  // all the usual private           // Widget stuff    Counter c;};     //or:// inherit from Counter to count objectsclass Widget: public Counter {    .....  // all the usual public           // Widget stuffprivate:    .....  // all the usual private           // Widget stuff};            
      对于Widget本身来说,Counter完成了任务。然而,如果我们在同一进程中还需要利用Counter来计数Fish类,显然,Counter就不能胜任,因为它只有一个静态成员变量,它会将Widget和Fish的个数一起统计。这个方案不行,怎么办?用模板!如下:
    template<typename T>class Counter {public:    Counter() { ++count; }    Counter(const Counter&) { ++count; }    ~Counter() { --count; }    static size_t howMany()    { return count; }private:    static size_t count;};// this now can go in headertemplate<typename T> size_t Counter<T>::count = 0;            
    则上面的实现变成:
    // embed a Counter to count objectsclass Widget {public:    .....    static size_t howMany()    {return Counter<Widget>::howMany();}private:    .....    Counter<Widget> c;};//or:// inherit from Counter to count objectsclass Widget: public Counter<Widget> {        .....};      
      这样,其他类就可以使用Counter计数自己的实例了,它们将互不影响。
      上面两种方案都可正确实现计数,我们继续探讨这两种方案的优缺点。
      首先讲public继承,即class Widget: public Counter<Widget>这种方案:有经验的读者肯定会想到基类Counter的析构函数要变为虚函数。否则通过基类指针delete派生类时,结果未定义(可能导致程序crash或其他)
    Counter<Widget> *pw =  new Widget;  // get base class ptr to derived class object    ......delete pw; // yields undefined results if the base class lacks a virtual destructor                  
      但一旦Counter有虚析构函数,就会给类带入vTable,多占用了空间并影响客户类的效率。解决方法可以是将析构函数作为protected成员。这样就不能delete pw,因为它会导致编译错误。
    template<typename T>class Counter {public:    .....protected:    ~Counter() { --count; }    .....};   
      其次,Counter作为客户类的成员变量这种方案(这时Counter的析构函数必须public)。一个明显的缺点是客户类必须定义Counter为其成员变量同时还得定义一个inline函数以调用Counter类得HowMany函数。另一个较隐蔽的缺点:它增大了客户类所占用的内存。Counter类没有非静态成员变量,有人就可能会认为Counter对象的大小为0,其实不然,C++规定所有对象的大小最小必须为1字节。所以这用方案增加了客户类的大小。使用派生则不一样,基类size可以0,所以public继承方案不会增加客户类的大小。
      除了上面两种方案,还可以使用private继承,即class Widget: private Counter<Widget>。类似于第一种方案:
    class Widget: private Counter<Widget> {public:    // make howMany public    using Counter<Widget>::howMany;     ..... // rest of Widget is unchanged};            
    它直接防止下面的代码:
    Counter<Widget> *pw =  new Widget; 	//私有继承不允许这样转换            
      综合看来,public继承方案已经比较完善了。然而,还是有些值得注意的地方。假如有另一个类SpecialWidget,其继承于Widget,对类SpecialWidget的对象计数就只能如下:
    class SpecialWidget: public Widget,    public Counter<SpecialWidget> {public:    };            
      这样,对SpecialWidget的对象计数是正确的,但对Widget对象的计数是错误的。这时Widget的计数是Widget类的所有对象SpecialWidget类的所有对象的总和。为什么?因为每创建一个SpecialWidget对象,Widget构造函数就要调用一次,就增加一次计数。

    总结

      用模板实现的这个对象计数类可以满足绝大多数需求,但不适用于计数有继承关系的类。本文的核心思想来源于CUG上C++大师Scott Meyers的一篇文章并有所改动。   

     

    关于 程序设计 C++ 技巧 的新闻
    • C++ Builder构建算二十四点小游戏
    • C++ SDK+Symbian开发入门之部署
    • 用Visual C++在单文档界面中创建视图
    • 从C++到Java --理解面向对象是关键所在
    • C++中的 static 关键字
    【评论】【收藏本文】【打印】【关闭】
    上一篇文章:C++中的 static 关键字
    下一篇文章:从C++到Java --理解面向对象是关键所在
    讨论区
    查看
    已有 0 位对此新闻感兴趣的网友发表了看法
    匿名发表
    注册通行证 登陆
    图文阅读推荐
    全站资源
    • 微软官方入门教程19:轻松掌握Vista系统的快
    • 微软2008大冲击,预借Vista SP1力促Vista市
    • 在收件箱中获得 Windows Vista 的最新更新
    • 微软官方Vista入门教程全集19篇(Vista学院
    • Windows Vista 的成功将势不可挡
    • 快快抛弃Vista,拥抱XP SP3!你觉得呢?
    • 浅谈Vista系统关闭虚拟内存与使用内存盘加速
    • 嘿嘿,按下键盘上面的三个键,马上让你的Vi
    • Windows Vista的盗版率只有Windows XP的一半
    • 3DMark和PCMark Vantage新版将只支持Vista系
    阅读排行
    • Borland 发布C++ Builder 2006 RAD 环境
    • C/C++程序员应聘常见面试题深入剖析
    • Visual C++常用数据类型转换详解
    • C++中的 static 关键字
    • 利用VC++实现局域网实时视频传输
    • 浅谈C/C++内存泄漏及其检测工具
    • 英国投票否决C++/CLI 微软强攻ISO标准受挫
    • VC++下用MSComm控件实现串口通讯
    • 伪随机数生成及在VC++中的实现
    • VC++编程实现对波形数据的频谱分析
    最新技术文档
    • C++中用赋值形式op=取代单独形式op
    • C++启蒙之用C++制作程序
    • C++启蒙之C++中的类
    • 解析C++/CLI之头文件、内联函数与数组
    • C++启蒙之控制结构
    • C++启蒙之注释符号
    • 了解C++异常处理的系统开支
    • C++语言学习之从结构到类
    • C++中理解“传递参数”和异常之间的差异
    • C++中禁止异常信息传递到析构函数外
    专题教程
    • 大话G游 专题:手机病毒揭密
    • ARP攻击防范与解决方案 路由故障处理手册
    • Picasa中文版_Picasa教程 专题:清除流氓软件
    • Firefox专题 seo搜索引擎优化专区
    • 重装Windows必知的事情 装机之必备软件大行动
    病毒专杀栏
    • 杀毒软件反被病毒杀 连"救命"都不能喊
    • 金山ARP防火墙
    • 还原卡神话破灭“机器狗”病毒来势汹汹
    • cctv经济半小时:你的手机现在安全吗?
    • 新挂马方式开始流行 ARP挂马称雄局域网
    • 木马和病毒清除的通用解法
    • IP地址不再冲突 查找ARP攻击者元凶
    • 教你几招识别和防御Web网页木马
    • 分析:封杀BT只是暂时的止痛药
    • QQ爆危险漏洞,“QQ游戏邀请大盗”邀请你玩病
    关于我们 | 诚聘英才 | 联系我们 | 版权声明 | 网站大事 | 网站地图 | 意见建议
    CopyRight 2005-2007 Jztop.Com 版权所有 未经许可 请勿转载