c++ 奇特的递归模板模式(CRTP)
概述
使用派生类作为模板参数特化基类。
与多态的区别
- 多态是动态绑定(运行时绑定),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<子类>接口函数(Interface和StaticInterface)调用其他成员函数,可以通过使用不同的模板实参来实例化模板实现不同的接口调用效果。
- 通过在
应用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)的更多相关文章
- 模板与继承之艺术——奇特的递归模板模式(CRTP)
一.什么是CRTP 奇特的模板递归模式(Curiously Recurring Template Pattern)即将派生类本身作为模板参数传递给基类. template<typename T& ...
- C++奇异递归模板模式
虚函数的问题 虚函数的主要问题是性能开销比较大,一个虚函数调用可能需要花费数倍于非虚函数调用的时间,尤其是当非虚函数被声明为inline时(注意,虚函数不能被内联). CRTP介绍 CRTP的全称是C ...
- JAVA设计模式之模板模式
在阎宏博士的<JAVA与模式>一书中开头是这样描述模板方法(Template Method)模式的: 模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式 ...
- Java设计模式之模板模式(Template )
前言: 最近学习了Glide开源图片缓存框架,在学习到通过使用ModelLoader自定义数据源的时候,Glide巧妙的使用了Java的模板模式来对外暴露处理不同的Url数据源,今天来学习总结一下模板 ...
- Java设计模式(七) 模板模式
[模板模式]在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤. 1,定义模板类 package com.pattern ...
- 模板模式与策略模式/template模式与strategy模式/行为型模式
模板模式 模版模式,又被称为模版方法模式,它可以将工作流程进行封装,并且对外提供了个性化的控制,但主流程外界不能修改,也就是说,模版方法模式中,将工作的主体架构规定好,具体类可以根据自己的需要,各自去 ...
- 12. 星际争霸之php设计模式--模板模式
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- 模板模式(C++) 【转】
模板模式(template)在面向对象系统的设计和开发过程中,一定会有这样的情况:对于一些功能,在不同的对象身上展示不同的作用,但是功能的框架是一样的,这就是模板(template)模式的用武之地,我 ...
- Head First 设计模式系列之一----模板模式(java版)
开篇序言:四人帮的设计模式对于我这个菜鸟看着打瞌睡,后面果断买了一本head first的,感觉还可以像看报纸似的,花了一个寒假的晚上看了大半,确实内容也挺吸引人的,讲的很风趣.否则我也不可能,大过年 ...
随机推荐
- Objective-C中的属性机制
Objective-C 2.0中的属性机制为我们提供了便捷的获取和设置实例变量的方式,也可以说属性为我们提供了一个默认的设置器和访问器的实现.在学习OC中属性之前我们先要知道为什么要为变量实现gett ...
- 关于css中pointer-events属性的怪异行为
在我的记忆中pointer-events就是用来进行事件穿透的,也就是说,如果给父元素设置了pointer-events:none,那么父元素不再监听鼠标事件事件(类似于touch,click这样的) ...
- 《HelloGitHub月刊》第07期
最近工作上的事比较多,<HelloGitHub>月刊第07期拖到月底才发. 本期月刊对logo和月刊的排版进行了优化,不知道大家的反馈如何,还望大家多多反馈,让<HelloGitHu ...
- HTML 网页特效CSS大全
css属性代码大全一CSS文字属性:color : #999999; /* 文字颜色*/font-family : 宋体,sans-serif; /* 文字字体*/font-size : 9pt; / ...
- 【Java】子类的链式调用
记录最近在项目设计中遇到的一个小问题. 前提:有这样两个POJO类,它们都可以通过链式调用的方式来设置其属性值,其中一个类继承了另一个类. 问题:通过链式调用,子类对象访问父类方法后,如何使返回对象仍 ...
- 代码的坏味道(2)——过大的类(Large Class)
坏味道--过大的类(Large Class) 特征 一个类含有过多字段.函数.代码行. 问题原因 类通常一开始很小,但是随着程序的增长而逐渐膨胀. 类似于过长函数,程序员通常觉得在一个现存类中添加新特 ...
- 我的angularjs源码学习之旅2——依赖注入
依赖注入起源于实现控制反转的典型框架Spring框架,用来削减计算机程序的耦合问题.简单来说,在定义方法的时候,方法所依赖的对象就被隐性的注入到该方法中,在方法中可以直接使用,而不需要在执行该函数的时 ...
- Java进击C#——语法之知识点的改进
本章简言 上一章我们讲到关于面向对象思想上C#和JAVA之差别.笔者分别从面向对象的三大特性入手.而本章主要讲一些C#改进的知识点.在.NET Framework 2.0之后出现很多新的知识点.这些知 ...
- 彻底解决“从客户端中检测到有潜在危险的Request.Form值”
类似设置validateRequest="false"的方法不推荐,因为应用程序需要显式检查所有输入,不方便. 1.前端使用encodeHtml函数对字符串进行编码,例: var ...
- Asp.net mvc返回Xml结果,扩展Controller实现XmlResult以返回XML格式数据
我们都知道Asp.net MVC自带的Action可以有多种类型,比如ActionResult,ContentResult,JsonResult……,但是很遗憾没有支持直接返回XML的XmlResul ...