1.泛型编程
void Swap(int& left, int& right) {
int temp = left;
left = right;
right = temp; }
void Swap(double& left, double& right) {
double temp = left;
left = right;
right = temp; }
void Swap(char& left, char& right) {
char temp = left;
left = right;
right = temp; }
我们看上面这段代码,以前C语言的话,要实现不同类型变量的交换就要写多个函数
但是在C++中就可以告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。
模版又分为函数模版和类模版
2.函数模版
template<typename T>
void Swap(T& t1, T& t2)
{
T tmp = t1;
t1 = t2;
t2 = tmp;
}
int main()
{
int a1 = 0;
int a2 = 1;
Swap(a1, a2);
cout << a1 << ' ' << a2 << endl;
double b1 = 0.2;
double b2 = 1.4;
Swap(b1, b2);
cout << b1 << ' ' << b2 << endl;
return 0;
}
直接看代码,这里有两个关键字,为template和typename,他俩的作用主要是将类型命名为T
根据传入参数,来推测T的类型,这个叫做推演
其实并不是只调用的一个函数,而是调用的两个函数,为int时会建立T为int的函数,为double时会建立T为double的函数,这叫函数模版的实例化
所以说这并不会提高效率,麻烦的只是编译器了,但是方便的程序员就可以了
还有就是typename可以用class代替,两个是一样的作用在这里,但不能用struct代替
这一段代码会出问题主要是因为编译器不知道T是什么类型,你这样传过去,T既可以是int也可以是double,所以编译器会出错
处理方法一:将一个进行强制类型转换
template<typename T>
T Add(const T& t1,const T& t2)
{
return t1 + t2;
}
int main()
{
int a1 = 0;
double a2 = 3.3;
Add(a1, (int)a2);
return 0;
}
如图我们将a2这个double类型强制类型转换,因为强制类型转换会生成临时变量,临时变量又具有常性,所以我们要用const修饰,在函数那里,所以说,如果有引用和指针的,如果不修改值的话,还是用const加上吧,不然很容易发生权限的缩小
template<typename T>
T Add(const T& t1,const T& t2)
{
return t1 + t2;
}
int main()
{
int a1 = 0;
double a2 = 3.3;
Add<int>(a1,a2);
return 0;
}
方法二就是显示实例化了,就是在函数名后面,参数前面加上就表示直接认为T为int了,那这样的话,a2这个double类型就会发生隐式类型转换了
template<typename T1,class T2>
auto Add(const T1& t1, const T2& t2)
{
return t1 + t2;
}
int main()
{
int a1 = 0;
double a2 = 3.3;
cout << Add(a1, a2);
return 0;
}
第三种方法就是在定义一个T,多对一个类型命名,那这样就可以根据int推出T1为int,根据为double类型推出T2为double,然后函数返回值不知道为什么好的话就用auto吧,自动判断,因为你不知道T1与T2谁为double,不知道返回谁好
int Add(int a1, int a2)
{
cout << "int Add(int a1, int a2)" << endl;
return a1 + a2;
}
template<typename T>
T Add(const T& t1, const T& t2)
{
cout << "T Add(const T& t1, const T& t2)" << endl;
return t1 + t2;
}
template<typename T1,class T2>
auto Add(const T1& t1, const T2& t2)
{
cout << "auto Add(const T1& t1, const T2& t2)" << endl;
return t1 + t2;
}
int main()
{
int a1 = 0,a2=9;
double b1 = 3.3,b2=9.3;
Add(a1, a2);
Add(b2, b1);
Add(a1, b1);
return 0;
}
因为模版并不是创建了这个函数,所以模版间是可以同时存在的
这个我们可以看出,函数调用是调用最适合的,同时为int时,因为有现成的,所以就调用这个
同时为double时,调用第二个,第一个也可以调用,但是不适合,因为会发生隐式类型转换
调用第三个也不是最合适的,因为是两个相同的,那就调用相同的就可以了啊
第三个,一个为int,一个为double,那就调用第三个最合适了
int main()
{
int a1 = 0,a2=9;
double b1 = 3.3,b2=9.3;
Add<int,int>(a1, b1);
Add<int>(b1, a1);
Add<double>(b1, a1);
return 0;
}
可以看出,多个参数的显示实例化,也就是<int,int>了,这个表示将T1,T2都弄为int,因为显示实例化的两个,所以调用第三个
Add(b1, a1);这个嘛,T Add(const T& t1, const T& t2)中的T就直接相当于变为了int,T1变为int,T2未知,这样的话,b1肯定要强制类型转换为int,那么都为int,选第二个呗
实例化就是指定那个T为什么,指定顺序与定义T的顺序一致
3.类模板
所谓类模板,就是对类创建一个模版
class Stack
{
public:
void Push(int x)
{
/
}
private:
int* _a;
int _size;
int _capacity;
};
如果不是模版的话就是这样的,现在直接变成模版
template<class T>
class Stack
{
public:
void Push(T x)
{
/
}
private:
T* _a;
T _size;
T _capacity;
};
int main()
{
Stack<int> s1;
Stack<double> s2;
return 0;
}
这个就相当于模版了,只不过调用模版的时候一定要显示实例化,因为这个不像函数,可以根据参数来得出T的类型,当然如果函数也不能根据参数类型来得出T,也只能显示实例化了
4.STL简介
STL叫做标准模板库,里面主要包括数据结构与算法,还包括一些什么内存池,仿函数,迭代器,配接器之类的东西
反正STL很重要
总结
这一节比较简单,主要是给STL开个头,下一节我们讲string,也就是串