c++主要提供两种模板函数模板和类模板
注意:使用模板时必须确定出通用数据类型T,并且能够推导出一致类型
1,函数模板的作用:
建立一个通用函数,其函数返回值类型和参数类型可以不具体制定,用一个虚拟的类型来代表。
template:关键字template表明是声明模板。typename可以用class代替,cal名称可以替换叫做通用数据类型。
#include<iostream>
using namespace std;
template<typename cal>
void swap(int &a,int &b)
{
int temp;
temp = a;
a = b;
b = temp;
}
void swap(double& a, double& b)
{
double temp;
temp = a;
a = b;
b = temp;
}
int main()
{
double a=20;
double b = 10;
//swap(a,b);//1,自动类型推导
swap<double>(a, b);//2,显示指定类型
char c='a';
swap(a,c);//两个数据不一样错误
cout << a <<" "<< b << endl;
}
1.1普通函数与函数模板调用的差别
一般情况下我们写了函数模板就不会在写普通函数
#include<iostream>
using namespace std;
template<typename T>//模板函数必须与模板声明连着写否者会报错
T myadd(T a, T b)
{
return a + b;
}
int myadd2(int a, int b)
{
return a + b;
}
int main()
{
int a = 10;
int b = 20;
char c = 'c';
cout << myadd2(a, b) << endl;//普通函数调用
cout << myadd2(a, c) << endl;//普通函数调用会出现自动隐式转换
//cout<<myadd(a,b)<<endl;//自动类型推导模板函数不会发生自动类型隐式转换
cout << myadd<int>(a, c) << endl;//显示指定类型模板函数不会发生自动类型隐式转换
return 0;
}
1.2普通函数与函数模板调用规则
编译器调用规则如下:
1,如果函数模板和普通函数都可以实现,优先调用普通函数。
2,可以通过空模板强制调用
3,函数模板可以发生函数重载
4,如果函数可以产生更好的匹配,优先调用函数模板
#include<iostream>
using namespace std;
template<typename T>
T myadd(T a, T b)
{
cout << "模板" << endl;
return a + b;
}
template<typename T>
T myadd(T a, T b,T c)
{
cout << "函数重载模板" << endl;
return a + b;
}
int myadd(int a, int b)
{
cout << "函数" << endl;
return a + b;
}
int main()
{
int a = 10;
int b = 20;
int d = 20;
char c = 'c';
cout << myadd(a, b) << endl;
cout << myadd(a, c) << endl;
cout << myadd<>(a, b) << endl;//可以通过空模板强制调用
cout << myadd<>(a, b,d) << endl;//函数重载模板
return 0;
}
2.1类模板
类模板的作用:
建立一个通用类,类中的数据类型可以不具体制定,用一个假的类型来代替。
template
注意:类模板中成员函数和普通类中成员函数创建时机是有区别的:
普通类中的成员函数一开始就可以创建
类模板中的成员函数在调用时才可以创建
#include<iostream>
#include<string>
using namespace std;
template<class NAME,class AGE>
class person
{
public:
person(NAME name,AGE age)
{
this->m_Name = name;
this->m_age = age;
}
void print()
{
cout<<this->m_age<<" "<<this->m_Name << endl;
}
public:
NAME m_Name;
AGE m_age;
};
int main()
{
person<string, int>a("NB", 9999999);
a.print();
return 0;
}
2.2类模板与函数模板的区别
a,类模板使用只能用显示指定类型方式
b,类模板中的模板参数列表可以有默认参数
建议使用显示指定类型这样可以便于维护
c,调用类模板函数时才初始化,因为类模板是未知类型
#include<iostream>
#include<string>
using namespace std;
template<class NAME,class AGE=int>
class person
{
public:
person(NAME name,AGE age)
{
this->m_Name = name;
this->m_age = age;
}
void print()
{
cout<<this->m_age<<" "<<this->m_Name << endl;
}
public:
NAME m_Name;
AGE m_age;
};
int main()
{
person<string, int>a("NB", 9999999);//显示指定
a.print();
person<string>b("NB2",6666666);
b.print();
return 0;
}
2.3类模板对象做函数参数
a,指定传入类型–直接显示对象的数据类型(常用)
b,参数模块化—将对象中的参数变为模板进行传递
c,整个类模板化 – 将这个对象类型模板化进行传递
#include<iostream>
#include <typeinfo>
#include<string>
#include <string>
using namespace std;
template<class T1, class T2>
class person
{
public:
void showperson()
{
cout << m_Name << ":" << m_Age << endl;
}
person(T1 name, T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
T1 m_Name;
T2 m_Age;
};
void print(person<string, int>& p)//指定传入类型--直接显示对象的数据类型
{
p.showperson();
}
template<class T1, class T2>
void print1(person<T1, T2>& p)//参数模块化---将对象中的参数变为模板进行传递
{
p.showperson();
cout << "T1:" << typeid(T1).name() << endl;
cout << "T2:" << typeid(T2).name() << endl;
}template<class T>
void print2(T &p)// 整个类模板化 -- 将这个对象类型模板化进行传递
{
p.showperson();
cout << typeid(T).name();
}
int main()
{
person<string, int>p("NB", 6666);
print2(p);
return 0;
}
2.4模板类继承
如果父类是类模板,子类需要指定出父类中T的数据类型
如果不指定,编译器无法给子类分配内存
如果想灵活指定出父类中T的类型,子类也需变为类模板
#include<iostream>
using namespace std;
template<class T1>
class base
{
public:
T1 a;
};
class son :public base<int>
{
public:
void show()
{
cout << "nnnn" << endl;
}
};
template<class T1, class T2>
class son2:public base<T2>
{
public:
son2()
{
cout << typeid(T1).name() << endl;
cout <<typeid(T2).name() << endl;
}
};
int main()
{
son2<int, char>p;
return 0;
}
类模板,类外实现
#include<iostream>
using namespace std;
template<class Nametype,class Agetype>
class base
{
public:
base(Nametype name,Agetype age);
Nametype m_name;
Agetype m_age;
};
template<class Nametype, class Agetype>//###########类模板,类外实现
base<Nametype,Agetype>::base(Nametype name, Agetype age)
{
this->m_age = age;
this->m_name = name;
}
int main()
{
base<string, int> p("孙悟空",9999999);
cout << p.m_name << p.m_age << endl;
return 0;
}