猫猫哥

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
//############################################################################
/*
 *  多态
 */

// 常见的动态多态
// Non-virtual Interface Idiom (NVI)

struct TreeNode {TreeNode *left, *right;};

class Generic_Parser {
   public:
   void parse_preorder(TreeNode* node) { //接口不是虚函数
      if (node) {
         process_node(node);
         parse_preorder(node->left);
         parse_preorder(node->right);
      }
   }
   private:
   virtual void process_node(TreeNode* node) { } //其中处理函数定义成虚函数
};

class EmployeeChart_Parser : public Generic_Parser {
   private:
   void process_node(TreeNode* node) {        //派生类可以定义自己的实现
       cout << "Customized process_node() for EmployeeChart.\n";
   }
};
   
int main() {
   ...
   EmployeeChart_Parser ep;
   ep.parse_preorder(root);
   ...
}
// 多态的好处:干净,优雅,通用的代码
/* 满足以下几点
 * 1. 基类和派生类之间是is-a关系
 * 2. 基类定义一个"通用"的算法,用来给派生类使用
 * 3. "通用"算法在派生类中定制
 */


/*
 * 虚函数的替换方案
 */
class A {
   X x;   // 动态地控制执行哪个任务

   /* X 可以是:
    * 1. 函数指针
    * 2. tr1::function, 一个归一化的函数指针
    * 3. 策略类
    */
   ...
};


struct TreeNode {TreeNode *left, *right;};

template <typename T>
class Generic_Parser {
   public:
   void parse_preorder(TreeNode* node) {
       if (node) {
           process_node(node);
           parse_preorder(node->left);
           parse_preorder(node->right);
       }
   }
   void process_node(TreeNode* node) {
       static_cast<T*>(this)->process_node(node);
   }
};

class EmployeeChart_Parser : public Generic_Parser<EmployeeChart_Parser> {
   public:
   void process_node(TreeNode* node) {
       cout << "Customized process_node() for EmployeeChart.\n";
   }
};
   
int main() {
   ...
   EmployeeChart_Parser ep; //对外界透明,就像是真的多态一样
   ep.parse_preorder(root);
   ...
}


// 用在库编程中比较多,比较看重虚表的开销
// 静态多态,会导致代码量膨胀,每个派生类的基类都是不同的类


// TMP Template Metaprogramming
// 将部分计算开销从运行时提前到编译时

// 也有将模板本身都叫做静态多态的,因为对于不同类型T,像<,=这样的运算符都是不同的

posted on 2018-12-25 00:55  猫猫哥  阅读(439)  评论(0编辑  收藏  举报