标签:
话题从重用开始说起:
最基本的重用,重用一个方法,被重用的逻辑被抽取封装成为方法,之后我们把方法当成一种工具来使用(处理数据,输入输出,或者改变状态)。
来到了面向对象的时代,如果这个方法出现父类上面就是继承,如果这个方法出现在其他对象上就是代理,如果子类想要重用父类的接口又不想重用实现那么就是多态。
但是这些重用都是基于相同的数据类型,方法创建出来后接收参数都是固定的类型,对于多态,可以通过子类来实现不同行为,但是方法总归还是接收一个固定父类型(或者接口)参数。
想想有没有这样的需求,两个完全不同的类型,他们之间不存在继承关系,但是却需要同样的处理逻辑,比如说各种类型都需要排序,比如说各种类型都有集合处理的需求。
那么能不能让方法接收不同类型来实现重用呢?C++的Template就是解决这样问题。
模板方法
既然这样需求不同类型却需要相同处理方法,所以有了模板方法,
template<typename T> T Add(T a, T b) { return a + b; }; int main() { string s1 = "Hello"; string s2 = "World"; cout << Add(12,13) << endl; cout << Add(s1,s2) << endl;
return 0;
}; 输出: 25 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(2,3) << endl; cout << c.Minus(9,5) << 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(2,3) << endl; cout << sc.Minus(9,5) << endl; cout << sc.Multi(9,5) << endl; return 0; }; 输出 8,4,45
从具体类继承
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(2,3) << endl; cout << sc.Minus(9,5) << endl; cout << sc.Multi(9,5) << endl; return 0; }; 输出 7, 4, 45
模板特例化(偏特化)
模板类可以通过继承可以在垂直方向变化,但是类型本身也是一个水平的维度,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(5)->PrintInfo(); return 0; }; 输出 Hello Common Hello Common Hello Int
如果一个模板类需要接受两个或者两个以上的类型来实现具体类,当其中一个类型是某个具体类的时候有特殊的行为,那么就成为偏特化。
继承是垂直方向上的特例化,但是特例化不是传统面向对象体系中的概念,可以类比但不要混淆,特例化是是另外一个维度(水平),因此特例化不仅仅可以作用在类上,也能作用在模板方法上。
比较
>>模板和模板模式(Template Method Design Pattern)
这个设计模式也是来解决不同类型的却有相同的处理逻辑,这个思想是一致的。但是实现却不同,模板模式由子类去实现模板方法的每一个步骤(或者某个步骤),而且这个模式的假设是所有的类型都是来自于相同的基类,没有解决我们最开始非固定类型。C++模板实现逻辑在类型外面(怎么感觉又有点像策略模式,但是策略模式需要相同的接口或者基类),而类型本身可以针对不同基类的类型。其实对于模板类(方法)而言,他们虽然没有共同的基类,但是再仔细想想,要在一个模板类中类型需要有一个抽象共性,但是这个共性不是以基类形式来表达,比如说排序,那么输入类型必须都要能比较大小,比如说集合,那么输入类型都要有“一个一个”的概念(好像不好理解,vector能处理流体问题吗?)
>>模板和宏
这两个东西很容易放在一起说,比如一个简单模板类可以通过宏来实现没有问题。
但是两者是从不同角度来解决重用问题的,模板是为不同类型提供相同逻辑的重用,是站在类型的角度上看问题。宏是为代码级别的重用,站在少写代码的角度来看问题。
所以他们有重叠的部分。也提供对方不能提供的功能
标签:
原文地址:http://www.cnblogs.com/kentax/p/5159035.html