话题从重用开始说起:

最基本的重用,重用一个方法,被重用的逻辑被抽取封装成为方法,之后我们把方法当成一种工具来使用(处理数据,输入输出,或者改变状态)。

来到了面向对象的时代,如果这个方法出现父类上面就是继承,如果这个方法出现在其他对象上就是代理,如果子类想要重用父类的接口又不想重用实现那么就是多态。

但是这些重用都是基于相同的数据类型,方法创建出来后接收参数都是固定的类型,对于多态,可以通过子类来实现不同行为,但是方法总归还是接收一个固定父类型(或者接口)参数。

想想有没有这样的需求,两个完全不同的类型,他们之间不存在继承关系,但是却需要同样的处理逻辑,比如说各种类型都需要排序,比如说各种类型都有集合处理的需求。

那么能不能让方法接收不同类型来实现重用呢?C++的Template就是解决这样问题。

模板方法

既然这样需求不同类型却需要相同处理方法,所以有了模板方法,

template<typename T>
T Add(T a, T b)
{
return a + b;
}; int main()
{
string s1 = "Hello";
string s2 = "World";
cout << Add(,) << endl;
cout << Add(s1,s2) << endl;
    return 0;
}; 输出:  HelloWorld

模板类

方法都能模板化,那么类怎么能够不模板化, 作为面向对象的C++,所以有了模板类

把这些模板方法组合起来,再加上模板成员就形成了一个模板类,这些概念和行为和一般的类是一样的。

template<typename T>
class Calculator
{
public:
T m_variable;
virtual T Add(T a, T b)
{
return a + b;
}; T Minus(T a, T b)
{
return a - b;
};
}; int main()
{
Calculator<int> c;
cout << c.Add(,) << endl;
cout << c.Minus(,) << endl; string s1 = "Hello";
string s2 = "World";
Calculator<string> d;
cout << d.Add(s1,s2) << endl;
//cout << d.Minus(s1,s2) << endl;
    return 0
} 

想想为什么最后那句注释可以编译过,但是打开那句就编译不过了。

我的理解,当模板类实例化的过程,如果没有用到的方法不会被加入被实例化的模板类中,除非你显示调用了模板类的方法。

模板类继承

既然是类,当然不能少了继承,模板类的继承可以分为

直接从模板类继承

template<typename T>
class SuperCalculator : public Calculator<T>
{
public:
T m_variable;
virtual T Add(T a, T b)//多态
{
return a + b + b;
}; T Multi(T a, T b)//子类
{
return a * b;
};
}; int main()
{
SuperCalculator<int> sc;
cout << sc.Add(,) << endl;
cout << sc.Minus(,) << endl;
cout << sc.Multi(,) << endl;
return ;
}; 输出 ,,

从具体类继承

class SuperIntCalculator: public Calculator<int>
{
public:
virtual int Add(int a, int b)
{
return a + b + a;
}; int Multi(int a, int b)
{
return a * b;
};
}; int main()
{
SuperIntCalculator sc;
cout << sc.Add(,) << endl;
cout << sc.Minus(,) << endl;
cout << sc.Multi(,) << endl; return ;
}; 输出 , ,

模板特例化(偏特化)

模板类可以通过继承可以在垂直方向变化,但是类型本身也是一个水平的维度,C++为这个维度提供了变化,对于某种具体类的模板类可以拥有特殊的行为,因此我们成为特例化。

template<typename T>
class TClass
{
public:
void PrintInfo()
{
printf("Hello common\n");
};
}; template<>
class TClass<int>//特例化
{
public:
void PrintInfo()
{
printf("Hello int\n");
};
}; template<typename T>
TClass<T> * GetTClassObject(T a)
{
return new TClass<T>;
}; int main()
{
GetTClassObject("Hello")->PrintInfo();
GetTClassObject(4.5)->PrintInfo();
GetTClassObject()->PrintInfo(); return ;
}; 输出
Hello Common
Hello Common
Hello Int

如果一个模板类需要接受两个或者两个以上的类型来实现具体类,当其中一个类型是某个具体类的时候有特殊的行为,那么就成为偏特化。

继承是垂直方向上的特例化,但是特例化不是传统面向对象体系中的概念,可以类比但不要混淆,特例化是是另外一个维度(水平),因此特例化不仅仅可以作用在类上,也能作用在模板方法上。

比较

>>模板和模板模式(Template Method Design Pattern)

这个设计模式也是来解决不同类型的却有相同的处理逻辑,这个思想是一致的。但是实现却不同,模板模式由子类去实现模板方法的每一个步骤(或者某个步骤),而且这个模式的假设是所有的类型都是来自于相同的基类,没有解决我们最开始非固定类型。C++模板实现逻辑在类型外面(怎么感觉又有点像策略模式,但是策略模式需要相同的接口或者基类),而类型本身可以针对不同基类的类型。其实对于模板类(方法)而言,他们虽然没有共同的基类,但是再仔细想想,要在一个模板类中类型需要有一个抽象共性,但是这个共性不是以基类形式来表达,比如说排序,那么输入类型必须都要能比较大小,比如说集合,那么输入类型都要有“一个一个”的概念(好像不好理解,vector能处理流体问题吗?)

>>模板和宏

这两个东西很容易放在一起说,比如一个简单模板类可以通过宏来实现没有问题。

但是两者是从不同角度来解决重用问题的,模板是为不同类型提供相同逻辑的重用,是站在类型的角度上看问题。宏是为代码级别的重用,站在少写代码的角度来看问题。

所以他们有重叠的部分。也提供对方不能提供的功能

C++ template随笔的更多相关文章

  1. Kooboo CMS 无聊随笔(2)

    上次写了一篇博客 http://www.cnblogs.com/kmsfan/p/Kooboo_CMS_suibi.html 作为这个系列的开篇,简单的介绍了一下Kooboo CMS的一些基本情况和界 ...

  2. 63、django之模版层(template)

    上篇主要介绍了django的MTV模型,主要介绍了视图层之路由配置系统url分发和视图层之视图函数view,本篇主要讲解MTV模型中的模版层template. 模版层(template) 一.模版简介 ...

  3. django之模版层(template)

    上篇主要介绍了django的MTV模型,主要介绍了视图层之路由配置系统url分发和视图层之视图函数view,本篇主要讲解MTV模型中的模版层template. 本篇导论: 模版简介 模版之变量 模版之 ...

  4. JavaWeb随笔整理

    JavaWeb随笔整理 为方便阅读,故整理了相关学习笔记 前端相关 HTML CSS JavaScript BootStrap 数据库相关 MySQL基础 MySQL表的约束和数据库设计 MySQL多 ...

  5. Vue3 框架基础随笔 (一)

    VUE框架基础部分随笔 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架. Vue可以使用简单的代码实现一个单页面应用. 基本格式 Vue通过模板语法来声明式的将数 ...

  6. 为.NET Core项目定义Item Template

    作为这个星球上最强大的IDE,Visual Studio不仅仅提供了很多原生的特性,更重要的是它是一个可定制的IDE,比如自定义Project Template和Item Template就是一个非常 ...

  7. jQuery.template.js 简单使用

    之前看了一篇文章<我们为什么要尝试前后端分离>,深有同感,并有了下面的评论: 我最近也和前端同事在讨论这个问题,比如有时候前端写好页面给后端了,然后后端把这些页面拆分成很多的 views, ...

  8. AI人工智能系列随笔

    初探 AI人工智能系列随笔:syntaxnet 初探(1)

  9. 【置顶】CoreCLR系列随笔

    CoreCLR配置系列 在Windows上编译和调试CoreCLR GC探索系列 C++随笔:.NET CoreCLR之GC探索(1) C++随笔:.NET CoreCLR之GC探索(2) C++随笔 ...

随机推荐

  1. 机器学习(4)之Logistic回归

    机器学习(4)之Logistic回归 1. 算法推导 与之前学过的梯度下降等不同,Logistic回归是一类分类问题,而前者是回归问题.回归问题中,尝试预测的变量y是连续的变量,而在分类问题中,y是一 ...

  2. 用C#实现网络爬虫(一)

    网络爬虫在信息检索与处理中有很大的作用,是收集网络信息的重要工具. 接下来就介绍一下爬虫的简单实现. 爬虫的工作流程如下 爬虫自指定的URL地址开始下载网络资源,直到该地址和所有子地址的指定资源都下载 ...

  3. 多线程+fork 引发的bug查找

    1. 问题描述 某个server SA是一个多线程服务器,主线程会调用fork,再exec生成工作进程SB. 实际上,SA的主线程fork出了一个子线程,但没有执行exec. # ps ajxf | ...

  4. 利用Asio搭建日志系统

    Asio(http://think-async.com)官方示例中给出了一个比较初步的日志服务,主要代码在basic_logger.hpp.logger_service.hpp.logger_serv ...

  5. 【HDOJ】1726 God’s cutter

    简单DP. /* 1726 */ #include <cstdio> #include <cstring> #include <cstdlib> #define M ...

  6. 怎样在WIN7系统下安装IIS和配置ASP(详细)

    一:Windows7系统 (IIS是WIN7自带的,版本7.0),首先是安装IIS.打开控制面板,找到“程序与功能”,点进去,点击左侧“打开或关闭Windows功能”,找到“Internet 信息服务 ...

  7. Java 中 MongoDB 使用指南

    一.引入MongoDB Java Driver包 如果需要操作MongoDB的Java项目是一个Maven项目,可以在依赖中加上以下的配置. <dependencies> <depe ...

  8. MVC路由机制

      按照传统,在很多Web框架中(如经典的ASP.JSP.PHP.ASP.NET等之类的框架),URL代表的是磁盘上的物理文件.例如,当看到请求http://example.com/albums/li ...

  9. [置顶] Hibernate运行机理

    Hibernate 的缓存体系 一级缓存: Session 有一个内置的缓存,其中存放了被当前工作单元加载的对象. 每个Session 都有自己独立的缓存,且只能被当前工作单元访问. 二级缓存: Se ...

  10. iOS_15_通过代码自己定义cell_微博UI

    终于效果图: BeyondTableViewController.h // // BeyondTableViewController.h // 15_代码自己定义cell_weibo // // Cr ...