概述

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

与多态的区别

  • 多态是动态绑定(运行时绑定),CRTP是静态绑定(编译时绑定)
  • 在实现多态时,需要重写虚函数,因而这是运行时绑定的操作。
  • CRTP在编译期确定通过基类来得到派生类的行为,它通过派生类覆盖基类成员函数来实现静态绑定的。

例子1

说明:

  • 父类调用直接子类函数的方法:

    • 静态函数成员:this 指针不可见,而对于某一个实例化的继承层次来说,只有一个静态类,因此使用Derived::memberfun()实现
    • 非静态函数成员:调用非静态成员函数时,必须通过对象或者对象指针,因此将this指针进行静态转换。static_cast(this)
  • 函数成员的覆盖
    如果子类中有和父类相同名称的函数(不管是否静态),父类版本被屏蔽。
  • 其他
    通过子类的对象或者对象指针调用其成员函数时,总是优先在其定义中寻找可行函数,如果没有找到,就执行父类的实现版本

crtp.h

#include<iostream>
#include<stddef.h>
using namespace std;
template<class Derived>
struct Base
{
void Interface()
{
cout <<"come from Interface"<<endl;
// 转换为子类指针,编译期将绑定至子类方法
static_cast<Derived*>(this)->Implementation();
} static void StaticInterface()
{
// 编译期将绑定至子类方法
cout <<"come from StaticInterface"<<endl;
Derived::StaticImplementation();
} void Implementation()
{
cout <<"Base Implementation"<<endl;
return;
}
static void StaticImplementation()
{
cout << "Base StaticImplementation"<<endl;
return;
}
}; // The Curiously Recurring Template Pattern (CRTP)
struct Derived1 : Base<Derived1>
{
static void StaticImplementation();
}; struct Derived2 : Base<Derived2>
{
void Implementation();
};

crtp.cc

void Derived1::StaticImplementation()
{
cout << "StaticImplementation from Derived1"<<endl;
return;
}
void Derived2::Implementation()
{
cout <<"Implementation from Derived2"<<endl;
return;
}
  • test-crtp.cc
int main()
{
cout << "***********************************" << endl;
Derived1 derive1;
Derived2 derive2;
derive1.Implementation();
derive1.StaticImplementation();
derive2.Implementation();
derive2.StaticImplementation();
cout << "***********************************" << endl << endl; Base<Derived1> base_derive1;
Base<Derived2> base_derive2;
base_derive1.Implementation();
base_derive1.StaticImplementation();
base_derive2.Implementation();
base_derive2.StaticImplementation();
cout << "***********************************" << endl << endl; base_derive1.StaticInterface();
base_derive1.Interface();
base_derive2.StaticInterface();
base_derive2.Interface();
cout << "***********************************" << endl << endl; return 0;
}

运行结果如下:

***********************************
Base Implementation
StaticImplementation from Derived1
Implementation from Derived2
Base StaticImplementation
*********************************** Base Implementation
Base StaticImplementation
Base Implementation
Base StaticImplementation
*********************************** come from StaticInterface
StaticImplementation from Derived1
come from Interface
Base Implementation
come from StaticInterface
Base StaticImplementation
come from Interface
Implementation from Derived2
***********************************

总结

  • 第一组结果说明:

    • 如果子类中有和父类相同名称的函数(不管是否静态),父类版本被屏蔽。
    • 如果子类中没有找到成员函数,就执行父类的实现版本
  • 第二组结果说明:
    • 通过Base<子类>对象调用成员函数时,就和通过Base对象调用成员函数一样的效果,不管实例化模板使用的模板实参是什么
  • 第三组结果说明:
    • 通过在Base<子类>接口函数(InterfaceStaticInterface)调用其他成员函数,可以通过使用不同的模板实参来实例化模板实现不同的接口调用效果。

应用1:实现计数

统计每个类的对象个数

template <typename T>
struct counter
{
counter(){ objects_created++;objects_alive++;}
virtual ~counter(){--objects_alive;}
static int objects_created;
static int objects_alive;
};
// 类外初始化
template <typename T> int counter<T>::objects_created( 0 );
template <typename T> int counter<T>::objects_alive( 0 );
class X : counter<X>{// ...};
class Y : counter<Y>{ // ...};
//X和Y类都有自己的计数

应用2:实现对象的引用计数

  • ns3中simple-ref-count.h

此处m_count是对象的成员变量

template <typename T, typename PARENT = empty, typename DELETER = DefaultDeleter<T> >
class SimpleRefCount : public PARENT
{
public:
SimpleRefCount (): m_count (1){}
inline void Ref (void) const
{
m_count++;
}
inline void Unref (void) const
{
m_count--;
if (m_count == 0)
{
DELETER::Delete (static_cast<T*> (const_cast<SimpleRefCount *> (this)));
}
}
mutable uint32_t m_count;
};
  • ns3中某一个需要计数的类
class Object : public SimpleRefCount<Object, ObjectBase, ObjectDeleter>
{
.....
}

c++ 奇特的递归模板模式(CRTP)的更多相关文章

  1. 模板与继承之艺术——奇特的递归模板模式(CRTP)

    一.什么是CRTP 奇特的模板递归模式(Curiously Recurring Template Pattern)即将派生类本身作为模板参数传递给基类. template<typename T& ...

  2. C++奇异递归模板模式

    虚函数的问题 虚函数的主要问题是性能开销比较大,一个虚函数调用可能需要花费数倍于非虚函数调用的时间,尤其是当非虚函数被声明为inline时(注意,虚函数不能被内联). CRTP介绍 CRTP的全称是C ...

  3. JAVA设计模式之模板模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述模板方法(Template Method)模式的: 模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式 ...

  4. Java设计模式之模板模式(Template )

    前言: 最近学习了Glide开源图片缓存框架,在学习到通过使用ModelLoader自定义数据源的时候,Glide巧妙的使用了Java的模板模式来对外暴露处理不同的Url数据源,今天来学习总结一下模板 ...

  5. Java设计模式(七) 模板模式

    [模板模式]在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤. 1,定义模板类 package com.pattern ...

  6. 模板模式与策略模式/template模式与strategy模式/行为型模式

    模板模式 模版模式,又被称为模版方法模式,它可以将工作流程进行封装,并且对外提供了个性化的控制,但主流程外界不能修改,也就是说,模版方法模式中,将工作的主体架构规定好,具体类可以根据自己的需要,各自去 ...

  7. 12. 星际争霸之php设计模式--模板模式

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...

  8. 模板模式(C++) 【转】

    模板模式(template)在面向对象系统的设计和开发过程中,一定会有这样的情况:对于一些功能,在不同的对象身上展示不同的作用,但是功能的框架是一样的,这就是模板(template)模式的用武之地,我 ...

  9. Head First 设计模式系列之一----模板模式(java版)

    开篇序言:四人帮的设计模式对于我这个菜鸟看着打瞌睡,后面果断买了一本head first的,感觉还可以像看报纸似的,花了一个寒假的晚上看了大半,确实内容也挺吸引人的,讲的很风趣.否则我也不可能,大过年 ...

随机推荐

  1. No zuo no die:DDD 应对具体业务场景,Domain Model 重新设计

    写在前面 上联:no zuo no die why you try 下联:no try no high give me five 横批: let it go上联:no zuo no die why y ...

  2. 学习Linux下s3c2440的USB鼠标驱动笔记

    1.ARM-Linux下USB驱动程序开发1.1.1.linux下USB配置:*********(MassStorage:存储设备)********************************** ...

  3. DocX在C#中的基本操作方法

    用了一个星期把园子里2016年中有关.net的文章都看了,有些只是大致的看了一下,在看的同时也在记录一些通用的方法.发现有很多对NPOI的文档,主要是操作Excl的方法,却很少有关文档类型的方法. 在 ...

  4. Azure Backup (2) Azure备份服务

    <Windows Azure Platform 系列文章目录> 本文介绍的是国内由世纪互联运维的Azure China. 本文介绍的Azure管理界面是Classic Model,网址:h ...

  5. AngularJS中的JSONP实践

    欢迎大家指导与讨论: ) 概念 首先呢,Json和JSONP是不一样的哦.Json呢,是众多数据存储的其中一种格式,是数据书写方式的其中一种.好比是大中华众多诗体的一种(比如说是七言诗吧).这种诗体规 ...

  6. 50个新的汉化Demo!纯前端 Wijmo 放大招

    Wijmo 是为企业应用程序开发而推出的一系列包含 HTML5 和 JavaScript 的开发控件,包含 Wijmo 5 . Wijmo 3 及面向企业级应用的控件金融图表.FlexSheet 和 ...

  7. Java中, for循环经典例子

    循环的两种应用:穷举和迭代. break跳出整个循环 一.穷举:将所有可能的情况都走一遍,用if筛选出符合条件. 百鸡百钱: 一只公鸡1文钱,一只母鸡2文钱,一只小鸡半文钱,需要买100只鸡, 正好花 ...

  8. MATLAB连接ACCESS数据库

    1.创建Windows系统ODBC数据源<打开控制面板----管理工具----ODBC数据源(32位或64位)----添加----安装数据源的驱动程序Microsoft Access Drive ...

  9. 去 IOE,MySQL 完胜 PostgreSQL

    本文转载自: http://www.innomysql.net/article/15612.html (只作转载, 不代表本站和博主同意文中观点或证实文中信息) 前言 上周参加了2015年的中国数据库 ...

  10. PowerDesigner16 基本使用教程

    一.基本概念 概念数据模型也称信息模型,它以实体-联系(Entity-RelationShip,简称E-R)理论为基础,并对这一理论进行了扩充. 它从用户的观点出发对信息进行建模,主要用于数据库的概念 ...