deepway

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  1 Posts :: 9 Stories :: 1 Comments :: 0 Trackbacks

常用链接

留言簿(4)

我参与的团队

搜索

  •  

最新评论

  • 1. re: 软件运行日志[未登录]
  • 我觉得调试日志不应该只记录软件的非正常过程吧,而是记录软件的运行过程。期间有不正常的时候用warning,error和fetal来记录。
  • --hi


问题描述:
   在 C++ 面向对象编程中,常常会遇到“类型识别”的需求:已知某个对象的基类型指针,需要识别该对象的派生类型,访问派生类型的公有函数。简单说就是,将基类型指针转换为派生类型指针,并用来访问派生类型的公有函数。

问题分析: 
   “类型识别”本质上是一个从抽象转为具象的过程,破坏了对象抽象性。虽不值得提倡,但在具象化情景下,“类型识别”又是必须的。
   “类型识别”常规方法是强制类型转换。这需要先定义一个“对象类型”枚举表,再在基类里定义一个返回“对象类型”的函数。这种方法的缺点显而易见:
         1. 需要维护全局性的“对象类型”枚举表;
         2. 向基类型构造函数传入“对象类型”参数;
         3. 每次“类型转换”前,先要获得“对象类型”值,判断对象类型;
   “类型识别”的另一种标准方法是RTTI。作为一项 C++ 编译选项,RTTI 直接将上述常规方法教给编译器做了。然而,这样也是有缺点的:
         1. RTTI会引入额外的开销。这是可以理解的,问题是RTTI这种开销会附加到所有类型上去;
         2. RTTI要求所有库都以RTTI方式编译,才能正常工作。而现实世界总是复杂的,这一点未必总是能实现;
         3. 个人认为RTTI是一种过于形式化的东西,违反了 C++ 的简洁性、高效性原则;
         4. 个人认为RTTI的低层形式化的东西,很多时候,我们仍然需要定义不依赖于C++类的“对象类型”枚举表;
   阅读 WebKit 代码时,我看到了一种基于虚函数的“类型识别”方法,代码如下:
   class EventTarget {
   public:
        void ref() { refEventTarget(); }
        void deref() { derefEventTarget(); }

        virtual EventSource* toEventSource();
        virtual MessagePort* toMessagePort();
        virtual Node* toNode();
        virtual DOMWindow* toDOMWindow();
        virtual XMLHttpRequest* toXMLHttpRequest();
        virtual XMLHttpRequestUpload* toXMLHttpRequestUpload();

 在基类中,定义向派生类型的转换函数,并且返回为NULL。每个派生类型,重新实现向自身转换的转换函数,返回自身的指针。我感觉这种方法:
         1. 非常安全,使用方便;
         2. 效率相对比较高;
         3. 省却了全局性的“对象类型”枚举表,却带来了维护基类“转换函数”的负担;
         4. 造成了基类对派生类的依赖性,似乎不太好。

   在上述方法的基础上,设想了一种改进的方法,设计原则是“从基类型向派生类型转换的函数,应该放置在派生类中,以静态函数的方式定义”。具体方法如下:
         1. 基类定义 void* toXXXX() 和 bool isXXXX() 两个私有虚函数,用编程规范规定,禁止派生类直接访问它们。
         2. 派生类重定义上述函数。
         3. 派生类型定义 XXXX* toType(Base*) 和 bool isType(Base*)两个静态函数,内部实现就是通过上述私有虚函数完成的。
         4. 所有的“类型识别操作”都使用上述静态函数完成。

问题小结:
         上述四种方式,很难说哪一种方式更好,宜具体情况具体对待。
          我本人偏向于,使用最后一种方式作为C++编程规范和模式,因为,它更是一种接口规范,其内部实现可以改为前三种方法中的任何一种。至于它带来的些许工作量,我认为,在它成为一种工作规范后,那些少量代码仅仅只是一点点没有难度的机械性编程,完全可以忽略不计。如果不介意在代码中使用宏机制,那么更可以用宏来实现,那么只需定义编译宏就能就在三种方式之间任意切换。
         最后一种方式,体现了一种策略:当你想为基类定义一些与派生类相关的工具函数时,倒不如将其定义为派生类的静态函数,以避免派生类型对基类型的“污染”。

posted on 2010-06-28 20:21 maxime 阅读(598) 评论(0)  编辑 收藏 引用 所属分类: C++ 设计模式

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理