目录
前言
最近一直再看《Effective C++》改善程序与设计的55个具体做法一书,看来一遍有一些收获,这些经典的书是和反复看,有些似懂非懂的内容,随着时间推移会慢慢理解,其中第一条就是:视C++为一个联邦语言:C、Object-Oriented C++、Tempate c++、STL。实际项目中模板使用的并不多,每次使用的时候都是重新看一遍,在这里就做个总结。一、泛型编程
编程范式与泛型编程
编程范式(Programming Paradigm) 是某种编程语言的典型编程风格或者说是编程方式
泛型编程(Generic Programming) 最初提出时的动机很简单直接:发明一种语言机制,能够帮助实现一个通用的标准容器库。所谓通用的标准容器库,就是要能够做到,比如用一个List类存放所有可能类型的对象,这样的事情;熟悉一些其它面向对象的语言的人应该知道,如Java里面这是通过在List里面存放Object引用来实现的。Java的单根继承在这里起到了关键的作用。然而单根继承对C++这样的处在语言链底层的语言却是不能承受之重。此外使用单根继承来实现通用容器也会带来效率和类型安全方面的问题,两者都与C++的理念不相吻合。
泛型编程是一种编程风格,其中算法以尽可能抽象的方式编写,而不依赖于将在其上执行这些算法的数据形式。这个概念在1989年首次由David Musser和Alexander A. Stepanov提出。
范式编程的作用
简单的说,意义和作用有:
1、类型的参数化,就是可以把类型像方法的参数那样传递。这一点意义非凡。
2、泛型使编译器可以在编译期间对类型进行检查以提高类型安全,减少运行时由于对象类型不匹配引发的异常。
3、泛型方法,算法的复用。
总结一句话就是: 抽象出来所有类型的用法,写一个通用类,然后需要用到相同方法时,把具体类型传进去,在整个运行过程中都会保证数据安全,是不同类型相同方法的复用。
二、C++模板的用法(C++11)
1.函数模板
1.1写法
模板是在程序编译阶段实例化去检测去合法性,函数模板通常又分为隐式实例化 和显示实例化
配合C++11 auto和decltype使用。函数模板不是个函数,而是一系列函数的抽象。
template <class 类型参数1, class类型参数2, ...>
返回值类型 模板名(形参表)
{
函数体
}
但是为了便于理解,讲上述class 改为typename
template <typename 类型参数1, typename 类型参数2, ...>
一个函数模板的例子:
template<typename T>
T add(T &a,T &b)
{
T c;
c =a+b;
return c
}
1.2函数模板特例化
特例化也就是写法:
template <>
返回值类型 模板名(具体类型)
{
函数体
}
也就是说是模板的确定一种类型,是针对特例出来的模板,作用就是在函数重载的时候会出现想不到匹配不上,用特列化相当于告诉编译器匹配特例模板(模板特例化分为全部模板特例化和部分模板特例化,类模板适用于两种特例化,函数因为存在重载特性,只能全部模板特例化。)
2.类模板
2.1 类模板
#include<iostream>
#include<string>
using namespace std;
//类模板用于实现类所需数据的类型参数化
template<typename T1,typename T2 = int>//类模板可以指定一个默认参数类型,可以认为是部分特例化
class person
{
public:
person(T1 name,T2 age)
{
this->n_name =name;
this->n_age =age;
}
void printer()
{
cout<<"person.n_name:"<<this->n_name<<" "<<"person.n_age:"<<this->n_age<<endl;
}
private:
T1 n_name;
T2 n_age;
};
void main(){
//类型//person p;//类模板不能进行自动推导
person<string,int>p1("jojo",20);
p1.printer();
}
2.2类模板作为函数参数
//类模板
template<class NameType, class AgeType>
class Person{
public:
Person(NameType name, AgeType age){
this->mName = name;
this->mAge = age;
}
void PrintPerson(){
cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
}
public:
NameType mName;
AgeType mAge;
};
//类模板做函数参数
void DoBussiness(Person<string,int>& p){
p.mAge += 20;
p.mName += "_vip";
p.PrintPerson();
}
int main(){
Person<string, int> p("John", 30);
DoBussiness(p);
system("pause");
return EXIT_SUCCESS;
}
2.3类模板的派生类
#include<iostream>
#include<string>
using namespace std;
template<class nametaype,class agetype >
class person
{
public:
person(nametaype name,agetype age)
{
this->nname = name;
this->nage =age;
}
void showperson()
{
cout << "name: " << this->nname<< " age: " << this->nage<< endl;
}
private:
nametaype nname;
agetype nage;
};
//继承模板是必须告诉派生类T的类型,否则T无法分配内存
class teacher:public person<string,int>
{
public:
teacher(string name,int age):person(name,age){}
};
//派生类也是模板类
template<class T1,class T2,class T3>
class teacher1:public person<T2,T3>//用户指定类型
{
public:
teacher1(T1 a,T2 name,T3 age):person(name,age){}
T1 tmp;
void typeprint()
{
cout<<typeid(T1).name()<<endl;//输出a的类型
cout<<typeid(T2).name()<<endl;//输出name的类型
cout<<typeid(T3).name()<<endl;//输出age的类型
}
};
void main(){
teacher1<int,string,int>p1(10,"laowang",20);
p1.typeprint();
teacher p2("孙悟空",500);
p2.showperson();
}
3.可变长模板
可变参数模板和普通模板的语义是一样的,只是写法上稍有区别,声明可变参数模板时需要在typename或class后面带上省略号…:
template<typename... Types>
典型的一个打印信息的(递归的方式实现)
void print() {}
template<typename T, typename... Types>
void print(const T& firstArg, const Types&... args) {
std::cout << firstArg << " " << sizeof...(args) << std::endl;
print(args...);
}
4.模板元编程
见引用的文章
总结
提示:终于网上看了多篇文章之后有了一丢丢了解,曾经在实际项目中看到有人说使用模板写了一个生产消费模型,当时虽然知道一点,现在再看起来豁然开朗。
引用
1、 泛型编程
2、泛型编程思想
3、泛型的意义和作用
4、C++11 模板元编程
5、C++11可变参数模板(函数模板、类模板)