1. 程式人生 > >C++進階--靜態多型

C++進階--靜態多型

//############################################################################
/*
 *  多型
 */

// 常見的動態多型
// 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,像<,=這樣的運算子都是不同的