目录
一、函数模板
1、函数模板的概念
概念:c++提供的函数模板机制,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来表示,这个通用的函数称为模板函数
2、函数模板的语法
格式:
template<类型形式参数表>
类型 函数名(形式参数表)
{
代码块
}
//当模板函数和普通函数同时存在,优先调用普通函数
3、模板函数调用方式
(1)隐式调用
//不写入的参数类型,让编译器自己判断传入的是什么类型的数据
//模板函数不能自动发生隐式类型转换
int n1 = 100, n2 = 200;
Swap(n1, n2); //隐式调用
(2)显示调用
格式:
函数名<类型列表> (实参列表)
//在调用时说明传入的类型参数
Swap<char>(c1, c2); //显示调用
4、函数模板的使用
#include <iostream>
using namespace std;
/*int add(int x,int y) //当模板函数和普通函数同时存在,优先调用普通函数
{
cout<<"普通函数"<<endl;
return x + y;
}*/
/*double add(double x,double y)
{
return x + y;
}*/
template <typename T> //声明虚拟类型T,作用范围到这个函数结束
T add(T x, T y)
{
return x + y;
}
template <typename T1,typename T2>
void print(T1 x,T2 y)
{
cout<<x<<" "<<y<<endl;
}
int main(int argc, char const *argv[])
{
int a = 100,b = 200;
double c = 4.32,d = 9.789;
cout<<add(a,b)<<endl;
cout<<add(c,d)<<endl;
//cout<<add(1,2.222)<<endl; //模板函数不能进行隐式类型转换 隐式调用
cout<<add<int>(1,2.222)<<endl; //显示调用
print(a,d);
print<double,char>(1.11,97);
return 0;
}
二、类模板
1、类模板的概念
类模板中定义的函数类型可以用在类声明和类实现中,类模板的目的是将数据的类型参数化。
2、类模板的语法
template <typename 类型参数1, typename 类型参数2>
class 类型{
.......
}
//类模板创建对象一定要显示调用
3、类模板的使用
#include <iostream>
using namespace std;
template <typename T,typename U>
class Test
{
private:
T a;
U b;
public:
Test(T a, U b)
{
this->a = a;
this->b = b;
}
void show()
{
cout<<a<<" "<<b<<endl;
}
};
int main(int argc, char const *argv[])
{
Test<int,char> t(1,'a'); //类模板创建对象一定要显示调用
t.show();
return 0;
}
4、模板的继承
//模板类派生普通类,继承的同时对基类进行实列化(指明基类的具体类型)
//模板类派生模板类,继承时可以不需要对基类进行实列化(基类类型可以不指明)
#include <iostream>
using namespace std;
template <typename T>
class Parent
{
protected:
T a;
public:
Parent(T a)
{
this->a = a;
}
void show()
{
cout<<"a = "<<a<<endl;
}
};
class Child:public Parent<int> //模板类派生普通类,继承的同时对基类实例化
{
public:
Child(int a):Parent<int>(a) //构造函数同样需要实例化
{
}
void show()
{
cout<<"a = "<<a<<endl;
}
};
template <typename F,typename U>
class Child2:public Parent<F> //模板类派生模板类,继承的同时不需要对parent实例化
{
private:
U b;
public:
Child2(F a,U b):Parent<F>(a)
{
this->b = b;
}
void show()
{
cout<<this->a<<" "<<b<<endl;
}
};
int main(int argc, char const *argv[])
{
Child c1(2);
c1.show();
Child2<int,double> c2(1,2.222);
c2.show();
return 0;
}
5、模板中关于函数的声明
//函数在类外部时,需要重写模板
#include <iostream>
using namespace std;
template <typename T,typename U>
class Test
{
private:
T a;
U b;
public:
Test(T a, U b);
void show();
};
template <typename T,typename U>
Test<T,U>::Test(T a, U b)
{
this->a = a;
this->b = b;
}
template <typename T,typename U>
void Test<T,U>::show()
{
cout<<a<<" "<<b<<endl;
}
int main(int argc, char const *argv[])
{
Test<int,char> t(1,'a'); //类模板创建对象一定要显示调用
t.show();
return 0;
}
6、模板中的static
//类中的 static 修饰的变量,需要在类外部进行初始化
//成员变量在初始化之前,需要重写模板
//static 修饰的成员变量,按模板进行分配,换句话说,相同的模板,用的是同一个static 成员变量
#include <iostream>
using namespace std;
template <typename T,typename U>
class Test
{
private:
T a;
U b;
public:
static int count;
public:
Test(T a, U b);
void show();
};
template <typename T,typename U>
int Test<T,U>::count = 0;
template <typename T,typename U>
Test<T,U>::Test(T a, U b)
{
this->a = a;
this->b = b;
count++;
}
template <typename T,typename U>
void Test<T,U>::show()
{
cout<<a<<" "<<b<<endl;
}
int main(int argc, char const *argv[])
{
Test<int,char> t1(1,'a');
Test<int,char> t2(1,'a');
Test<int,char> t3(1,'a');
Test<int,char> t4(1,'a');
Test<int,char> t5(1,'a');
Test<int,double> t6(1,1.11);
Test<int,double> t7(2,1.11);
Test<int,double> t8(3,1.11);
cout<<Test<int,char>::count<<endl; //count = 5
cout<<Test<int,double>::count<<endl; //count = 3
return 0;
}
练习:改错
#include <stdio.h>
struct test{
int a;
int b;
};
void func(struct test *tt)
{
struct test *lt;
lt = &tt[0];
printf("[0] a : %d,b:%d\n",lt->a,lt->b);
lt = &tt[1];
printf("[1] a : %d,b:%d\n",lt->a,lt->b);
lt = &tt[2];
printf("[2] a : %d,b:%d\n",lt->a,lt->b);
return;
};
int main(int argc, char const *argv[])
{
struct test lm[3] = {{1,2},{11,22},{111,222}};
struct test llm = {333,444};
func(lm);
func(&llm);
return 0;
}
上述代码,错误在于数组作为函数传参时,需要传两个方面的值:数组首地址、数组大小;