C++惯用法:奇特的递归模板模式(Curiously Recurring Template Pattern,CRTP,Mixin-from-above)

http://blog.csdn.net/lifesider/article/details/6527653

意图:

使用派生类作为模板参数特化基类。

 

与多态的区别:

多态是动态绑定(运行时绑定),CRTP是静态绑定(编译时绑定)

 

在实现多态时,需要重写虚函数,因而这是运行时绑定的操作。

然而如果想在编译期确定通过基类来得到派生类的行为,CRTP便是一种独佳选择,它是通过派生类覆盖基类成员函数来实现静态绑定的。

 

范式:

[cpp]  view plain  copy
  1. class derived : public base<derived>  
  2. {  
  3.     // attributes and behaviors  
  4. }  

 

示例代码:

[c-sharp]  view plain  copy
  1. template <class Derived>  
  2.   struct base  
  3.   {  
  4.       void interface()  
  5.       {  
  6.           // 转换为子类指针,编译期将绑定至子类方法  
  7.           static_cast<Derived*>(this)->implementation();  
  8.       }  
  9.    
  10.       static void static_interface()  
  11.       {  
  12.           // 编译期将绑定至子类方法  
  13.           Derived::static_implementation();  
  14.       }  
  15.    
  16.       // 下面两个方法,默认实现可以存在,或者应该被继承子类的相同方法覆盖  
  17.       void implementation();  
  18.       static void static_implementation();  
  19.   };  
  20.    
  21.   // The Curiously Recurring Template Pattern (CRTP)  
  22.   struct derived_1 : base<derived_1>  
  23.   {  
  24.       // 这里子类不实现,将使用父类的默认实现  
  25.       //void implementation();  
  26.    
  27.       // 此方法将覆盖父类的方法  
  28.       static void static_implementation();  
  29.   };  
  30.    
  31.   struct derived_2 : base<derived_2>  
  32.   {  
  33.       // 此方法将覆盖父类的方法  
  34.       void implementation();  
  35.    
  36.       // 这里子类不实现,将使用父类的默认实现  
  37.       //static void static_implementation();  
  38.   };  

 

缺点:

CRTP由于基类使用了模板,目前的编译器不支持模板类的导出,因而不能使用导出接口。

 

其它使用领域:

在数值计算中,往往要对不同的模型使用不同的计算方法(如矩阵),一般使用继承提供统一接口(如operator运算符),但又希望不损失效率。这时便又可取CRTP惯用法,子类的operator实现将覆盖基类的operator实现,并可以编译期静态绑定至子类的方法。

 

英文链接:http://en.wikibooks.org/wiki/More_C++_Idioms/Curiously_Recurring_Template_Pattern

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个使用归回溯和迭代回溯算来解决0-1背包问题的C++程序示例: ```cpp #include <iostream> #include <vector> using namespace std; struct Item { int weight; int value; }; int max(int a, int b) { return (a > b) ? a : b; } // 归回溯算 int recursiveBacktracking(vector<Item> items, int capacity, int index) { if (index < 0 || capacity == 0) { return 0; } if (items[index].weight > capacity) { return recursiveBacktracking(items, capacity, index - 1); } else { return max(recursiveBacktracking(items, capacity, index - 1), items[index].value + recursiveBacktracking(items, capacity - items[index].weight, index - 1)); } } // 迭代回溯算 int iterativeBacktracking(vector<Item> items, int capacity) { int n = items.size(); vector<vector<int>> dp(n + 1, vector<int>(capacity + 1)); for (int i = 0; i <= n; i++) { for (int w = 0; w <= capacity; w++) { if (i == 0 || w == 0) { dp[i][w] = 0; } else if (items[i - 1].weight <= w) { dp[i][w] = max(items[i - 1].value + dp[i - 1][w - items[i - 1].weight], dp[i - 1][w]); } else { dp[i][w] = dp[i - 1][w]; } } } return dp[n][capacity]; } int main() { vector<Item> items = {{10, 60}, {20, 100}, {30, 120}}; int capacity = 50; // 使用归回溯算求解 int max1 = recursiveBacktracking(items, capacity, items.size() - 1); cout << "归回溯算求解结果: " << max1 << endl; // 使用迭代回溯算求解 int max2 = iterativeBacktracking(items, capacity); cout << "迭代回溯算求解结果: " << max2 << endl; return 0; } ``` 在这个示例中,我们定义了一个`Item`结构体来表示每个物品的重量和价值。然后,我们实现了`max`函数来返回两个整数中较大的一个。 接下来,我们分别实现了归回溯算和迭代回溯算来解决0-1背包问题。 在`main`函数中,我们创建了一个包含三个物品的向量,并设置背包容量为50。然后,我们分别使用归回溯算和迭代回溯算来求解背包问题,并将结果输出到控制台。 你可以根据自己的需求修改物品向量和背包容量,运行程序以获取不同情况下的结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值