1.函数模板和类模板
函数:返回值,函数名,函数参数列表
函数形参列表:变量(变量类型)(变量名(值))
(1)void mySwap(char &a1,char &a2)...
void mySwap(double &a1,double &a2)...
void mySwap(int &a1,int &a2)...
(2)变量类型能否作为参数传递?
-----> 怎样将变量的类型作为参数传递?
-----> 模板
a:写一个普通函数
void Swap(char &a1,char &a2)...
b:将类型参数化:template (用来声明模板)<>(类型参数列表)
template <typename T>
void Swap(T &a1,T &a2)...
(3)Swap(a,b);//隐式调用,编译器会自己判断传过去的参数类型
Swap<double>(a,b)//显式调用,<变量类型>
2.模板使用
模板:将类型参数化--->将数据类型和数据本身进行分离
算法:将不必关心处理的是什么类型的数据
template <typename T,typename T1>
void mySort(T arr[],T1 len)...
#include <iostream>
using namespace std;
template <typename T>
void Swap(T &a,T &b)
{
T temp = a;
a = b;
b = temp;
}
template <typename T>
void bubble(T arr[],int len)
{
for(int i = 0;i < len-1;i++)
{
for(int j = 0;j < len-i-1;j++)
{
if(arr[j] > arr[j+1])
{
Swap(arr[j] , arr[j+1]);
}
}
//print(arr,len);
}
}
template <typename T>
void print(T arr[],int len)
{
for(int i = 0;i < len;i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
int main()
{
int arr[] = {10,9,8,7,6,5,4,3,2,1};
int len = sizeof(arr)/sizeof(arr[0]);
bubble<int>(arr,len);
print(arr,len);
char a[] = "wedfgasdghadsdfgnhmjawesrthym";
len = sizeof(a)/sizeof(a[0]);
bubble<char>(a,len-1);
print(a,len);
double b[] = {1.2,-3.4,5.6,-7.8,9.0};
len = sizeof(b)/sizeof(b[0]);
bubble<double>(b,len);
print(b,len);
return 0;
}
3.模板使用的注意事项
(1)a:
void mySwap(int &a,int &b)...
template <typename T>
void Swap(T &a,T &b)...
int a;
char c;
mySwap(a,c);//普通函数在参数传递的时候,可以进行参数的隐式转换
Swap(a,c);//模板函数不行,模板不支持隐式数据类型转换
print<int>(a,c);//非要用模板函数时
b:在普通函数和函数模板都可以调用的情况下,优先调用普通函数
c:print<>(a,b);//可以用空的参数列表<>来强制调用函数模板
(2)函数模板可以被重载
void print(T a,T b)...
void print(T a,T b,T c)...
(3)其实使用了函数模板,每种数据类型的函数并没有省略,只是由编译器自己来帮助补全的。
template <typename T>
void Swap(T &a,T &b)...
//下面这些函数全由编译器补全
void Swap(char &a,char &b)...
void Swap(int &a,int &b)...
void Swap(double &a,double &b)...
4.类模板
(1)类的模板
template <typename T>
class Complex
{
public:
Complex(T a,T b)
{
this->a = a;
this->b = b;
}
private:
T a;
T b;
}
(2)A:类模板去定义对象,必须要指明类型
Complex<int>a1(1,2);
Complex<double>b1(1.2,2.3);
B:对象做参数传递:
a:指明对象类型
b:定义成模板
void print(Complex<int>&a1)...//普通函数
template<typename T>
void print(Complex<T>&b1)...//模板函数
(3)派生类
A:派生自一个具体的类
class A:public Complex<int>...
B:派生一个类模板
template <typename T>
1.class B:public Complex<int>...
2.class B:public Complex<T>...
5.类模板使用:所有的类模板函数写在类的内部
#include <iostream>
using namespace std;
template <typename T>
class Complex
{
//<1>
friend ostream &operator<<(ostream &out,Complex<T> &a3)
{
out << a3.a << "+" << a3.b << "i";
return out;
}//有friend修饰,所以它是一个外部函数,不是类的内部函数,但是不能就这样将函数写在类的外部,编译不通过
/*<2>
friend Complex<T> operator+(Complex<T> &a1,Complex<T> &a2)
{
Complex<T> temp(a1.a+a2.a,a1.b+a2.b);
return temp;
}
*/
<3>
friend Complex<T> mySub(Complex<T> &c1,Complex<T> &c2)
{
Complex<T> temp(c1.a-c2.a,c1.b-c2.b);
return temp;
}//可以实现
//friend Complex<int> mySub(Complex<int> &c1,Complex<int> &c2);
//ostream &operator<<(ostream &out,Complex<int> &a3);
//friend Complex<int> operator+(Complex<int>&a1,Complex<int> &a2);
public:
Complex(T a,T b)
{
this->a = a;
this->b = b;
}
<2>
Complex<T> operator+(Complex<T> &a2)
{
Complex<T> temp(this->a+a2.a,this->b+a2.b);
return temp;
}//可以实现
<3>
/*Complex<T> mySub(Complex<T> &c2)
{
Complex<T> temp(this->a-c2.a,this->b-c2.b);
return temp;
}//可以实现*/
private:
T a;
T b;
};
<1>
//ostream &operator<<(ostream &out,Complex<int> &a3)
//{
// out << a3.a << "+" << a3.b << "i";
// return out;
//}//可以在外部实现
<1>
//template <typename T>
//Complex<T> mySub(Complex<T> &c1,Complex<T> &c2)
//{
// Complex<T> temp(c1.a-c2.a,c1.b-c2.b);
// return temp;
//}//在外部不能实现
<2>
//Complex<int> operator+(Complex<int> &a1,Complex<int> &a2)
//{
// Complex<int> temp(a1.a+a2.a,a1.b+a2.b);
// return temp;
//}//可以在外部实现
<2>
//template <typename T>
//Complex<T> operator+(Complex<T> &a1,Complex<T> &a2)
//{
// Complex<T> temp(a1.a+a2.a,a1.b+a2.b);
// return temp;
//}//不能在外部实现
<3>
//Complex<int> mySub(Complex<int> &c1,Complex<int> &c2)
//{
// Complex<int> temp(c1.a-c2.a,c1.b-c2.b);
// return temp;
//}//可以在外部实现
<3>
//template <typename T>
//Complex<T> mySub(Complex<T> &c1,Complex<T> &c2)
//{
// Complex<T> temp(c1.a-c2.a,c1.b-c2.b);
// return temp;
//}//不能实现
int main()
{
Complex<int> a1(1,2),a2(2,3),a3(0,0);
a3 = a1 + a2;
cout << a3 << endl;
a3 = mySub(a1,a2);
cout << a3 << endl;
return 0;
}
6.类的使用:所有的类模板函数写在类的外部
(1)类的内部函数在外部实现
A:类的内部成员函数在外部实现,必须全部写出函数模板
B:类名前加T
C:类的成员函数定义对象的时候,类型参数列表<T>,可写可不写
D:类的返回值,一定要加上类型参数列表<T>
#include <iostream>
using namespace std;
template <typename T>
class Complex;
template <typename T>
ostream &operator<< (ostream &out,Complex<T> &a3);
template <typename T>
Complex<T> mySub(Complex<T> &c1,Complex<T> &c2);
template <typename T>
class Complex
{
friend ostream &operator<< <T> (ostream &out,Complex &a3);
friend Complex<T> mySub <T> (Complex &c1,Complex &c2);
public:
Complex(T a,T b);
Complex<T> operator+(Complex<T> &a2);
private:
T a;
T b;
};
//类内部函数的外部实现
//1.类的内部成员函数在类的外部实现,必须全部写出函数模板
template <typename T>
//2.类名前加T
Complex<T>::Complex(T a,T b)
{
this->a = a;
this->b = b;
}
//3.类的成员函数定义对象的时候,类型参数列表<T>可写可不写
//4.类的返回值一定要加上类型参数列表<T>
template <typename T>
Complex<T> Complex<T>:: operator+(Complex &a2)
{
Complex temp(this->a+a2.a,this->b+a2.b);
return temp;
}
template <typename T>
Complex<T> mySub(Complex<T> &c1,Complex<T> &c2)
{
Complex<T> temp(c1.a-c2.a,c1.b-c2.b);
return temp;
}
template <typename T>
ostream &operator<< (ostream &out,Complex<T> &a3)
{
cout << a3.a << "+" << a3.b << "i";
return out;
}
int main()
{
Complex<int> a1(1,2),a2(2,3),a3(0,0);
a3 = a1 + a2;
cout << a3 << endl;
a3 = mySub<int>(a1,a2);
cout << a3 << endl;
return 0;
}
(2)类的友元函数在外部实现
A:需要在类前加 类的前置声明,函数的前置声明
B:在类的内部声明必须在函数名与参数列表直接加<T>,形参列表中可加可不加
C:友元函数外部实现,必须将参数列表中加<T>
D:友元函数外部实现,调用必须加<数据类型>
#include <iostream>
using namespace std;
//1.需要在类前加 类的前置声明,函数的前置声明
template <typename T>
class Complex;
template <typename T>
ostream &operator<< (ostream &out,Complex<T> &a3);
template <typename T>
Complex<T> mySub(Complex<T> &c1,Complex<T> &c2);
template <typename T>
class Complex
{
// 2.在类的内部声明必须在函数名与参数列表直接加<T>,形参列表中可加可不加
friend ostream &operator<< <T> (ostream &out,Complex &a3);
friend Complex<T> mySub <T> (Complex &c1,Complex &c2);
public:
Complex(T a,T b);
Complex<T> operator+(Complex<T> &a2);
private:
T a;
T b;
};
template <typename T>
Complex<T>::Complex(T a,T b)
{
this->a = a;
this->b = b;
}
template <typename T>
Complex<T> Complex<T>:: operator+(Complex &a2)
{
Complex temp(this->a+a2.a,this->b+a2.b);
return temp;
}
//友元函数的外部实现
//3.友元函数外部实现,必须将参数列表中加<T>
template <typename T>
Complex<T> mySub(Complex<T> &c1,Complex<T> &c2)
{
Complex<T> temp(c1.a-c2.a,c1.b-c2.b);
return temp;
}
template <typename T>
ostream &operator<< (ostream &out,Complex<T> &a3)
{
cout << a3.a << "+" << a3.b << "i";
return out;
}
int main()
{
Complex<int> a1(1,2),a2(2,3),a3(0,0);
a3 = a1 + a2;
cout << a3 << endl;
//4.友元函数外部实现,调用必须加<数据类型>
a3 = mySub<int>(a1,a2);
cout << a3 << endl;
return 0;
}
7.static变量在类模板中的使用
A:从类模板实例化的每个模板类有自己的类模板数据成员,该模板类的所有对象共享一个static数据成员
B:和非模板类的static数据成员一样,模板类的static数据成员也应该在文件范围定义和初始化
C:每个模板类有自己的类模板的static数据成员副本
函数:返回值,函数名,函数参数列表
函数形参列表:变量(变量类型)(变量名(值))
(1)void mySwap(char &a1,char &a2)...
void mySwap(double &a1,double &a2)...
void mySwap(int &a1,int &a2)...
(2)变量类型能否作为参数传递?
-----> 怎样将变量的类型作为参数传递?
-----> 模板
a:写一个普通函数
void Swap(char &a1,char &a2)...
b:将类型参数化:template (用来声明模板)<>(类型参数列表)
template <typename T>
void Swap(T &a1,T &a2)...
(3)Swap(a,b);//隐式调用,编译器会自己判断传过去的参数类型
Swap<double>(a,b)//显式调用,<变量类型>
2.模板使用
模板:将类型参数化--->将数据类型和数据本身进行分离
算法:将不必关心处理的是什么类型的数据
template <typename T,typename T1>
void mySort(T arr[],T1 len)...
#include <iostream>
using namespace std;
template <typename T>
void Swap(T &a,T &b)
{
T temp = a;
a = b;
b = temp;
}
template <typename T>
void bubble(T arr[],int len)
{
for(int i = 0;i < len-1;i++)
{
for(int j = 0;j < len-i-1;j++)
{
if(arr[j] > arr[j+1])
{
Swap(arr[j] , arr[j+1]);
}
}
//print(arr,len);
}
}
template <typename T>
void print(T arr[],int len)
{
for(int i = 0;i < len;i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
int main()
{
int arr[] = {10,9,8,7,6,5,4,3,2,1};
int len = sizeof(arr)/sizeof(arr[0]);
bubble<int>(arr,len);
print(arr,len);
char a[] = "wedfgasdghadsdfgnhmjawesrthym";
len = sizeof(a)/sizeof(a[0]);
bubble<char>(a,len-1);
print(a,len);
double b[] = {1.2,-3.4,5.6,-7.8,9.0};
len = sizeof(b)/sizeof(b[0]);
bubble<double>(b,len);
print(b,len);
return 0;
}
3.模板使用的注意事项
(1)a:
void mySwap(int &a,int &b)...
template <typename T>
void Swap(T &a,T &b)...
int a;
char c;
mySwap(a,c);//普通函数在参数传递的时候,可以进行参数的隐式转换
Swap(a,c);//模板函数不行,模板不支持隐式数据类型转换
print<int>(a,c);//非要用模板函数时
b:在普通函数和函数模板都可以调用的情况下,优先调用普通函数
c:print<>(a,b);//可以用空的参数列表<>来强制调用函数模板
(2)函数模板可以被重载
void print(T a,T b)...
void print(T a,T b,T c)...
(3)其实使用了函数模板,每种数据类型的函数并没有省略,只是由编译器自己来帮助补全的。
template <typename T>
void Swap(T &a,T &b)...
//下面这些函数全由编译器补全
void Swap(char &a,char &b)...
void Swap(int &a,int &b)...
void Swap(double &a,double &b)...
4.类模板
(1)类的模板
template <typename T>
class Complex
{
public:
Complex(T a,T b)
{
this->a = a;
this->b = b;
}
private:
T a;
T b;
}
(2)A:类模板去定义对象,必须要指明类型
Complex<int>a1(1,2);
Complex<double>b1(1.2,2.3);
B:对象做参数传递:
a:指明对象类型
b:定义成模板
void print(Complex<int>&a1)...//普通函数
template<typename T>
void print(Complex<T>&b1)...//模板函数
(3)派生类
A:派生自一个具体的类
class A:public Complex<int>...
B:派生一个类模板
template <typename T>
1.class B:public Complex<int>...
2.class B:public Complex<T>...
5.类模板使用:所有的类模板函数写在类的内部
#include <iostream>
using namespace std;
template <typename T>
class Complex
{
//<1>
friend ostream &operator<<(ostream &out,Complex<T> &a3)
{
out << a3.a << "+" << a3.b << "i";
return out;
}//有friend修饰,所以它是一个外部函数,不是类的内部函数,但是不能就这样将函数写在类的外部,编译不通过
/*<2>
friend Complex<T> operator+(Complex<T> &a1,Complex<T> &a2)
{
Complex<T> temp(a1.a+a2.a,a1.b+a2.b);
return temp;
}
*/
<3>
friend Complex<T> mySub(Complex<T> &c1,Complex<T> &c2)
{
Complex<T> temp(c1.a-c2.a,c1.b-c2.b);
return temp;
}//可以实现
//friend Complex<int> mySub(Complex<int> &c1,Complex<int> &c2);
//ostream &operator<<(ostream &out,Complex<int> &a3);
//friend Complex<int> operator+(Complex<int>&a1,Complex<int> &a2);
public:
Complex(T a,T b)
{
this->a = a;
this->b = b;
}
<2>
Complex<T> operator+(Complex<T> &a2)
{
Complex<T> temp(this->a+a2.a,this->b+a2.b);
return temp;
}//可以实现
<3>
/*Complex<T> mySub(Complex<T> &c2)
{
Complex<T> temp(this->a-c2.a,this->b-c2.b);
return temp;
}//可以实现*/
private:
T a;
T b;
};
<1>
//ostream &operator<<(ostream &out,Complex<int> &a3)
//{
// out << a3.a << "+" << a3.b << "i";
// return out;
//}//可以在外部实现
<1>
//template <typename T>
//Complex<T> mySub(Complex<T> &c1,Complex<T> &c2)
//{
// Complex<T> temp(c1.a-c2.a,c1.b-c2.b);
// return temp;
//}//在外部不能实现
<2>
//Complex<int> operator+(Complex<int> &a1,Complex<int> &a2)
//{
// Complex<int> temp(a1.a+a2.a,a1.b+a2.b);
// return temp;
//}//可以在外部实现
<2>
//template <typename T>
//Complex<T> operator+(Complex<T> &a1,Complex<T> &a2)
//{
// Complex<T> temp(a1.a+a2.a,a1.b+a2.b);
// return temp;
//}//不能在外部实现
<3>
//Complex<int> mySub(Complex<int> &c1,Complex<int> &c2)
//{
// Complex<int> temp(c1.a-c2.a,c1.b-c2.b);
// return temp;
//}//可以在外部实现
<3>
//template <typename T>
//Complex<T> mySub(Complex<T> &c1,Complex<T> &c2)
//{
// Complex<T> temp(c1.a-c2.a,c1.b-c2.b);
// return temp;
//}//不能实现
int main()
{
Complex<int> a1(1,2),a2(2,3),a3(0,0);
a3 = a1 + a2;
cout << a3 << endl;
a3 = mySub(a1,a2);
cout << a3 << endl;
return 0;
}
6.类的使用:所有的类模板函数写在类的外部
(1)类的内部函数在外部实现
A:类的内部成员函数在外部实现,必须全部写出函数模板
B:类名前加T
C:类的成员函数定义对象的时候,类型参数列表<T>,可写可不写
D:类的返回值,一定要加上类型参数列表<T>
#include <iostream>
using namespace std;
template <typename T>
class Complex;
template <typename T>
ostream &operator<< (ostream &out,Complex<T> &a3);
template <typename T>
Complex<T> mySub(Complex<T> &c1,Complex<T> &c2);
template <typename T>
class Complex
{
friend ostream &operator<< <T> (ostream &out,Complex &a3);
friend Complex<T> mySub <T> (Complex &c1,Complex &c2);
public:
Complex(T a,T b);
Complex<T> operator+(Complex<T> &a2);
private:
T a;
T b;
};
//类内部函数的外部实现
//1.类的内部成员函数在类的外部实现,必须全部写出函数模板
template <typename T>
//2.类名前加T
Complex<T>::Complex(T a,T b)
{
this->a = a;
this->b = b;
}
//3.类的成员函数定义对象的时候,类型参数列表<T>可写可不写
//4.类的返回值一定要加上类型参数列表<T>
template <typename T>
Complex<T> Complex<T>:: operator+(Complex &a2)
{
Complex temp(this->a+a2.a,this->b+a2.b);
return temp;
}
template <typename T>
Complex<T> mySub(Complex<T> &c1,Complex<T> &c2)
{
Complex<T> temp(c1.a-c2.a,c1.b-c2.b);
return temp;
}
template <typename T>
ostream &operator<< (ostream &out,Complex<T> &a3)
{
cout << a3.a << "+" << a3.b << "i";
return out;
}
int main()
{
Complex<int> a1(1,2),a2(2,3),a3(0,0);
a3 = a1 + a2;
cout << a3 << endl;
a3 = mySub<int>(a1,a2);
cout << a3 << endl;
return 0;
}
(2)类的友元函数在外部实现
A:需要在类前加 类的前置声明,函数的前置声明
B:在类的内部声明必须在函数名与参数列表直接加<T>,形参列表中可加可不加
C:友元函数外部实现,必须将参数列表中加<T>
D:友元函数外部实现,调用必须加<数据类型>
#include <iostream>
using namespace std;
//1.需要在类前加 类的前置声明,函数的前置声明
template <typename T>
class Complex;
template <typename T>
ostream &operator<< (ostream &out,Complex<T> &a3);
template <typename T>
Complex<T> mySub(Complex<T> &c1,Complex<T> &c2);
template <typename T>
class Complex
{
// 2.在类的内部声明必须在函数名与参数列表直接加<T>,形参列表中可加可不加
friend ostream &operator<< <T> (ostream &out,Complex &a3);
friend Complex<T> mySub <T> (Complex &c1,Complex &c2);
public:
Complex(T a,T b);
Complex<T> operator+(Complex<T> &a2);
private:
T a;
T b;
};
template <typename T>
Complex<T>::Complex(T a,T b)
{
this->a = a;
this->b = b;
}
template <typename T>
Complex<T> Complex<T>:: operator+(Complex &a2)
{
Complex temp(this->a+a2.a,this->b+a2.b);
return temp;
}
//友元函数的外部实现
//3.友元函数外部实现,必须将参数列表中加<T>
template <typename T>
Complex<T> mySub(Complex<T> &c1,Complex<T> &c2)
{
Complex<T> temp(c1.a-c2.a,c1.b-c2.b);
return temp;
}
template <typename T>
ostream &operator<< (ostream &out,Complex<T> &a3)
{
cout << a3.a << "+" << a3.b << "i";
return out;
}
int main()
{
Complex<int> a1(1,2),a2(2,3),a3(0,0);
a3 = a1 + a2;
cout << a3 << endl;
//4.友元函数外部实现,调用必须加<数据类型>
a3 = mySub<int>(a1,a2);
cout << a3 << endl;
return 0;
}
7.static变量在类模板中的使用
A:从类模板实例化的每个模板类有自己的类模板数据成员,该模板类的所有对象共享一个static数据成员
B:和非模板类的static数据成员一样,模板类的static数据成员也应该在文件范围定义和初始化
C:每个模板类有自己的类模板的static数据成员副本