目录
模板定义:
函数模板不是一个实在的函数,编译器不能为其生成可执行代码。定义函数模板后只是一个对函数功能框架的描述,当它具体执行时,将根据传递的实际参数决定其功能。模板分为函数模板和类模板。
函数模板:
定义语法:
template<typename T>
函数声明或定义
注意:在使用模板时,必须要能够推导出一致的数据类型T;模板必须要确定T的数据类型。其有两种调用方式:自动类型推导和显示指定类型俩种方式。
#include<iostream>
using namespace std;
template<typename T>//声明一个模板,告诉编译器T是一个通用数据类型
void myswap(T &a,T &b)
{
T temp=a;
a=b;
b=temp;
}
void test()
{
int a=1;
int b=2;
myswap<int>(a,b);//自动类型推导
cout<<a<<" "<<b<<endl;
myswap(a,b);//显示指定类型
cout<<a<<" "<<b<<endl;
}
template<typename T>
void func()
{
cout<<"func()"<<endl;
}
int main()
{
func<int>();
test();
return 0;
}
普通函数与函数模板区别:
1.普通函数可以发生隐式类型转换
2.函数模板若采用自动类型推导,则不能发生隐式类型转换
3.函数模板若采用显示指定类型,则可以发生隐式转换
普通函数与函数模板的调用规则:
1.如果都可以调用,则优先调用普通函数;
2.可以通过空模板参数列表强制调用函数模板
3.函数模板也可以发生重载
4.如果函数模板可以产生更好的匹配,则优先调用函数模板
#include <iostream>
using namespace std;
void func(int a ,int b)
{
cout<<"普通函数"<<endl;
}
template<typename T>
void func(T a,T b)
{
cout<<"函数模板"<<endl;
}
template <typename T>
void func(T a,T b,T c)
{
cout<<"函数模板重载"<<endl;
}
int main()
{
int a=10;
int b=20;
int c=30;
func(a,b);//普通函数
func<>(a,b);//函数模板
func(a,b,c);//函数模板重载
char d='c';
char e='e';
func(e,d);//函数模板可以实现更好的匹配
return 0;
}
局限性:
模板函数并不是万能的,特别是对于自定义数据类型,这个时候我们应该使用具体化的函数模板。
#include <iostream>
#include<string>
using namespace std;
class person
{
public:
string name;
int age;
person(string name,int age)
{
this->age=age;
this->name=name;
}
};
template<typename T>
bool mycompare(T &a,T &b)
{
return 0;
}
template<> bool mycompare(person &a,person &b)//具体化函数模板来调用person自定义数据类型
{
if (a.age==b.age&& a.name==b.name)
{
cout<<"相等"<<endl;
return true;
}
else
{
cout<<"不相等"<<endl;
return false;
}
}
int main()
{
person p1("张三",20);
person p2("李四",20);
bool res=mycompare(p1,p2);
return 0;
}
类模板:
定义:
template<class T>
类模板与函数模板的区别:
1.类模板没有自动类型推导的使用方式
2.类模板在模板参数列表中可以有默认参数
#include <iostream>
#include<string>
using namespace std;
template<class Nametype,class Agetype=int>//可以有默认参数
class Person
{
public:
Person(Nametype name,Agetype age)
{
this-> name=name;
this->age=age;
}
void print()
{
cout<<this->age<<" "<<this->name<<endl;
}
Nametype name;
Agetype age;
};
int main()
{
Person <string,int> p1("赵四",42);//不能Perosn p("赵四",42);
Person<string>p2("刘能",40);
p1.print();
p2.print();
return 0;
}
类模板中成员函数的创建时机:普通类的成员函数一开始就被创建,而类模板要在调用时才会创建
类模板对象作函数参数:
1.指定传入类型
2.参数模板化
3.整个类模板化
#include <iostream>
#include<string>
using namespace std;
template<class T1,class T2>
class Person
{
public:
T1 name;
T2 age;
Person(T1 name,T2 age)
{
this->name=name;
this->age=age;
}
void print()
{
cout<<"姓名"<<name<<"年龄"<<age<<endl;
}
};
void printperson1(Person<string,int>p)//指定传入类型
{
cout<<"姓名"<<p.name<<"年龄"<<p.age<<endl;
}
template<class T>
void printperson2(T p)//整个类模板化
{
cout<<"姓名"<<p.name<<"年龄"<<p.age<<endl;
}
template<class T1,class T2>//参数模板化
void printperson3(Person<T1,T2>p)
{
cout<<"姓名"<<p.name<<"年龄"<<p.age<<endl;
}
int main()
{
Person<string,int>p1("赵四",43);
printperson1(p1);
Person<string ,int>p2("刘能",42);
printperson2(p2);
Person<string,int>p3("谢广坤",44);
printperson3(p3);
return 0;
}
类模板与继承:
1.当子类继承的父类是一个模板时,子类在声明的时候,需要指出父类中T的类型
2.如果想要灵活指出父类中T的类型,子类也需要变为类模板
#include<iostream>
#include<string>
using namespace std;
template<class T>
class base
{
T m;
};
class son1:public base<int>
{
};
template<class T1,class T2>
class son2:public base<T2>
{
T1 obj;
};
int main()
{
son1 s1;
son2<int ,char>s2;
return 0;
}
类模板成员函数类外实现:
#include <iostream>
#include<string>
using namespace std;
template<class T1,class T2>
class Person
{
public:
T1 name;
T2 age;
Person(T1 name,T2 age);
void showperson();
};
template<class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age)
{
this->age=age;
this->name=name;
}
template<class T1,class T2>
void Person<T1,T2>::showperson()
{
cout<<name<<" "<<age<<endl;
}
int main()
{
Person <string ,int>p("Tom",10);
p.showperson();
return 0;
}
类模板分文件实现:
1.直接引用源文件
2.源文件和头文件写一起,成.hpp文件
方法一:
//person.h
#pragma once
#include<iostream>
#include<string>
using namespace std;
template<class T1,class T2>
class Person
{
public:
T1 name;
T2 age;
Person(T1 name,T2 age);
void showperson();
};
//person.cpp
#include "person.h"
#include<iostream>
using namespace std;
template<class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age)
{
this->age=age;
this->name=name;
}
template<class T1,class T2>
void Person<T1,T2>::showperson()
{
cout<<name<<" "<<age<<endl;
}
#include<iostream>
#include"person.cpp"
using namespace std;
int main()
{
Person <string ,int>p("Jack",10);
p.showperson();
return 0;
}
方法二:
//person.hpp
#pragma once
#include<iostream>
#include<string>
using namespace std;
template<class T1,class T2>
class Person
{
public:
T1 name;
T2 age;
Person(T1 name,T2 age);
void showperson();
};
template<class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age)
{
this->age=age;
this->name=name;
}
template<class T1,class T2>
void Person<T1,T2>::showperson()
{
cout<<name<<" "<<age<<endl;
}
#include<iostream>
#include"person.hpp"
using namespace std;
int main()
{
Person <string ,int>p("Jack",10);
p.showperson();
return 0;
}
类模板友元函数内外实现:
另外,还有类模板友元函数的类内类外实现,类内友元函数实现和上面的一样,照猫画虎而已,但类外实现有些许复杂。
#include <iostream>
#include<string>
using namespace std;
template<class T1,class T2>
class Person;
template<class T1,class T2>
void print_person2(Person<T1,T2>p)
{
cout<<p.name<<" "<<p.age<<endl;
}
template <class T1,class T2>
class Person
{
friend void print_person1(Person<T1,T2> p)//类内实现
{
cout<<p.name<<" "<<p.age<<endl;
}
public:
Person(T1 name ,T2 age)
{
this->name=name;
this->age=age;
}
friend void print_person2<>(Person<T1,T2>p);//类外实现,需要加载空模板参数列表,而且需要让编译器提前知道这个函数的存在
private:
T1 name;
T2 age;
};
void test01()
{
Person<string ,int>p1("Tom",10);
print_person1(p1);
}
void test02()
{
Person <string ,int>p2("Jack",6);
print_person2(p2);
}
int main()
{
test01();
test02();
return 0;
}