概述

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

与多态的区别

  • 多态是动态绑定(运行时绑定),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. Java多线程系列--“JUC锁”01之 框架

    本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下:01. Java多线程系列--“JUC锁”01之 框架02. Java多线程系列--“JUC锁”02之 互斥锁Reentrant ...

  2. 条形码的应用三-----------从Excel文件中读取条形码

    条形码的应用三------从Excel文件中读取条形码 介绍 上一篇文章,我向大家展示了生成多个条形码并存储到Excel文件中的一个方法.后来我又有了个想法:既然条码插入到excel中了,我可不可以从 ...

  3. Windows Server 2008 下解析二级域名的方法

    昨天去了客户那里部署网站,用的是客户那边的windows server 2008. 本文主要以总结问题点的形式来说. 问题1:本机的数据库是SQL SERVER 2008R2,客户那边的数据库是SQL ...

  4. Java中写文件操作

    OutputStream 和 Writer OutputStream类(直接操作byte数组) 该类是字节输出流的抽象类,定义了输出流的各种操作方法.如下图是OutputStream的层次结构: By ...

  5. springMVC学习笔记(二)-----注解和非注解入门小程序

    最近一直在做一个电商的项目,周末加班,忙的都没有时间更新博客了.终于在上周五上线了,可以轻松几天了.闲话不扯淡了,继续谈谈springMvc的学习. 现在,用到SpringMvc的大部分使用全注解配置 ...

  6. SQL Server 存储(1/8):理解数据页结构

    我们都很清楚SQL Server用8KB 的页来存储数据,并且在SQL Server里磁盘 I/O 操作在页级执行.也就是说,SQL Server 读取或写入所有数据页.页有不同的类型,像数据页,GA ...

  7. Net设计模式实例之单例模式( Singleton Pattern)

    一.单例模式简介(Brief Introduction) 单例模式(Singleton Pattern),保证一个类只有一个实例,并提供一个访问它的全局访问点.单例模式因为Singleton封装它的唯 ...

  8. Cocos2dx实现光影效果的两种方式

    Shader 和 RenderTexture 先贴上两张效果图 (Shader) (RenderTexture) 说一下实现的原因,因为项目中需要夜景,光影的效果.最初想到使用Shader来实现.实现 ...

  9. Nancy之Pipelines三兄弟(Before After OnError)

    一.简单描述 Before:如果返回null,拦截器将主动权转给路由:如果返回Response对象,则路由不起作用. After : 没有返回值,可以在这里修改或替换当前的Response. OnEr ...

  10. C#中正则表达式在replace中的应用!

    多少年来,许多的编程语言和工具都包含对正则表达式的支持,.NET基础类库中包含有一个名字空间和一系列可以充分发挥规则表达式威力的类,而且它们也都与未来的Perl 5中的规则表达式兼容.     此外, ...