1、模板
1、模板的使用
:template<typename 类型>
1.1、隐式调用:myswap(d1,d2);编译器自动判断类型,通知函数
1.2、显示调用: myswap(d1,d2);<>中写的是处理的数据类型
2、模板的实现机制
模板并不是真正的将数据类型传递给函数,数据类型是无法传递的,模板实际上是根据调用的时候来如果没有就创建相应的函数,有就直接调用。
模板的两次编译
2.1、对模板本身
2.2、调用时对调用的语句进行编译。
3、实例
#include <iostream>
using namespace std;
template <typename T>
void print(T a, T b)
{
cout << "a = " << a << ", b = " << b << endl;
}
void print(int a, int b)
{
cout << "int" << endl;
}
template <typename T, typename T2>
void print(T a, T2 b)
{
cout << "a = " << a << ", b = " << b << endl;
}
// 1、隐式调用过程中不支持类型的自动转换
// 2、当普通函数和函数模板都可以调用的时候,优先调用普通函数
// 3、当函数模板可以提供更优选择的时候,优先调用函数模板
// 4、函数模板支持重载
int main()
{
int a = 10;
int b = 20;
char c = 'A';
//print(a, c);
//print<int>(a, c);
print<char>(a, c);
//print(a, b);
//print(a, c);
return 0;
}
// 模板的实现机制:
// 模板并不是真的将类型作为参数进行传递
// 根据调用的时候来创建 相应类型的函数 ==> 模板: 生成函数的样本
// 模板两次编译:第一次是对模板本身编译,第二次是在调用对调用语句进行编译
// 函数模板 模板函数
int main2()
{
int a = 10;
int b = 20;
print<int>(a, b); // 编译器会找 print_ii 如果存在直接调用,如果不存在,通过模板进行创建
print<int>(a, b); //print_ii已经存在,会直接调用
print<double>(1.2, 3.4);
return 0;
}
2、函数模板
1、意义:为了将算法与数据类型分离,从而可以专心算法的研究不需要考虑类型的区分
2、注意点:
2.1、隐式调用过程中,不支持类型的自动转换,也就是说不能传2种类型的数据
2.2、当普通函数与函数模板都可以调用的时候,优先使用普通函数
2.3、但是,在函数模板可以提供更优选择的时候,使用函数模板。
2.4、函数模板可以重载
3、实例
#include <iostream>
using namespace std;
template <typename T>
void my_swap(T &a,T &b)
{
T tmp = a;
a = b;
b = tmp;
}
template <typename T>
void my_print(T a,T b)
{
cout<< "a = "<<a<<",b = "<<b<<endl;
}
template <typename T>
void my_sock(T *a, int len)
{
for(int i = 0;i < len-1;i++)
{
for(int j = 0;j < len-1-i;j++)
{
if(a[j]>a[j+1])
my_swap(a[j],a[j+1]);
}
}
}
template <typename T>
void my_print(T *a,int len)
{
for(int i = 0;i < len;i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
}
//模板---->实现算法与数据类型分离,可以专注算法。
int main1()
{
int a = 10;
int b = 20;
my_swap(a,b); //隐式调用
my_print(a,b);
double a1 = 1.34;
double b1 = 2.44;
my_swap<double>(a1,b1); //显示调用
my_print(a1,b1);
return 0;
}
//用模板写排序(冒泡)
int main()
{
int a[] = {4,3,2,1,5,22,4};
int len1 = sizeof(a)/sizeof(a[0]);
my_sock(a,len1);
my_print(a,len1);
double b[] = {-1.2,3.1,2.7,-1.7,5.1,-22.1,4.7};
double len2 = sizeof(b)/sizeof(b[0]);
my_sock(b,len2);
my_print(b,len2);
char c[]="sadadadsfsfgdfah";
double len3 = sizeof(c)/sizeof(c[0])-1;
my_sock(c,len3);
my_print(c,len3);
string d[]={"sas","sdfd","23effs","4323"};
double len4 = sizeof(d)/sizeof(d[0]);
my_sock(d,len4);
my_print(d,len4);
return 0;
}
3、类模板
1、类—>类模板:实现各种通用的数据类型
2、使用类模板的时候,禁止使用隐式转换(系统不知道你的类自然不能自动识别)
函数模板成员在类的外部进行实现,必须全部写成模板函数
#include <iostream>
using namespace std;
// 类模板
// 函数 ---> 函数模板 ---> 实现通用算法
// 类 ----> 类模板 ---> 实现各种通用的数据类型
template <typename T>
class Test
{
public:
Test(T a)
{
this->a = a;
}
void show()
{
cout << a << endl;
}
protected:
T a;
};
// 1、派生具体的类
class Child1 : public Test<int>
{
public:
Child1(int a, int b):Test<int>(a)
{
this->b = b;
}
private:
int b;
};
// 2、派生模板类
template <typename T>
class Child2 : public Test<T>
{
public:
Child2(T a, T b):Test<T>(a)
{
this->b = b;
}
private:
T b;
};
// 模板对象作为参数传递
// 1、写普通函数
void func(Test<int> &t)
{
t.show();
}
//2、模板函数
template <typename T>
void func1(Test<T> &t)
{
t.show();
}
// ******类模板不允许隐式调用
int main()
{
Test<int> t1(10);
t1.show();
Test<double> t2(1.2);
t2.show();
func(t1);
// func(t2);
func1<int>(t1);
func1<double>(t2);
return 0;
}
3、类模板的友元函数
3.1、友元函数在类之前声明
3.2、类要对函数进行友元声明
#include <iostream>
using namespace std;
template <typename T>
class Complex;
template <typename T>
ostream &operator <<(ostream &out,Complex<T> &c);
template <typename T>
class Complex
{
friend ostream &operator << <T>(ostream &out,Complex &c);
public:
Complex();
Complex(T a,T b);
Complex operator =(Complex &c);
void show();
private:
T a;
T b;
};
template <typename T>
Complex<T>::Complex(T a,T b)
{
this->a = a;
this->b = b;
}
template <typename T>
void Complex<T>::show()
{
if(b == 0)
cout << a;
else if(b < 0)
cout << a << " - "<<b*-1<<"i";
else if(b > 0)
cout << a << " + "<<b<<"i";
cout<<endl;
}
template <typename T>
ostream &operator <<(ostream &out, Complex<T> &c)
{
if(c.b == 0)
cout << c.a;
else if(c.b < 0)
cout << c.a << " - "<<c.b*-1<<"i";
else if(c.b > 0)
cout << c.a << " + "<<c.b<<"i";
return out;
}
template <typename T>
Complex<T> Complex<T>::operator =(Complex &c)
{
a = c.a;
b = c.b;
return *this;
}
int main()
{
Complex<int> c(1,2);
Complex<int> c1;
c.show();
cout<<c<<endl;
c1 = c;
c1.show();
return 0;
}
4、使用类模板与类的区别
类模板分文件写的时候,头文件要包含.cpp文件
写类模板的时候将实现文件命名为.hpp文件,表明是可以被包含的实现文件