模板的机制
模板并不是能处理任何类型的数据,只是它根据传入参数的类型的不同生成了不同的 函数/类 体(我们在不使用函数模板的正常操作,只不过编译器帮我们做了)。在此编译过程中,存在两次编译,一次是模板,一次是实例化的函数/类。
函数模板的定义
template <class V1,class V2…>// 或者 template < typename V1….> 告诉编译器 遇到变量V不要报错,可定义多个 V1 , V2……
void Exchange ( V1 a , V1 b)
{
V1 c=a;
a=b;
b=c;
}
函数模板的作用范围:
只对后面第一个函数有效
函数模板的调用
- 自动类型推导
int a=10, b=0;
Exchange(a,b);
- 显示的指定类型
Exchange<int>(a,b);
函数模板与普通函数的区别
- 普通函数在传参的时候可以进行类型转换。
- 函数模板在传参的时候 参数的类型必须一致
函数模板与普通函数的优先级
- 函数模板和普通函数同时存在且满足需求的时候,优先考虑普通函数。
- 如果非得调用模板函数,在调用函数名后加<>。
定义类模板
- 通常类模板的申明和定义写在同一文件,命名为.hpp,表明有类模板的文件。其他使用文件需要包含此.hpp
- 类中每个函数将如下定义
Template<class T>
Student<T>::Student()
{
}
类模板必须显示调用
Student <int> S1(1,2);
类模板的派生
子类在派生父类的时候,必须先确定父类的类型
template<class T>
class Student
{
private: T m_name;
}
//情况1,父类确定好类型
class Person:public Student<int>
{
}
//情况2,再重新定义个模板
template<class T>
class Person:public Student< T >
{
}
友元函数
- (1) 类前申明
template<class T1, class T2> class Student;
template<class T1, class T2> void Print(Student<T1, T2> p); - (2)类中声明
friend void Print<T1,T2>(Student<T1, T2> p); - (3)定义处
template<class T1, class T2>
void Print(Student<T1, T2> p)
{
cout << “name is :” << p.m_name << “age is:” << p.m_age << endl;
}
重载操作符在类模板中申明为友元
- 类前申明:
template<class T1, class T2> class Student;
template<class T1, class T2> ostrream& operator<< (ostrream& os Student<T1, T2> &p); - 类的申明:
template<class T1, class T2>
class Student
{
friend ostream& operator<< < T1, T2> (ostrream& os ,Student<T1, T2> &p);
} - 定义处:
template<class T1, class T2>
ostrream& operator<< < T1, T2> (ostrream& os ,Student<T1, T2> &p);
{
重载函数实现
}
类模板中申明static变量,每个实例化的类拥有各自的static变量,不进行共享,
student.hpp
template <class T>
class Student
{
public:
static int a;
}
template <class T>
int Student< T >::a = 0; //初始化
main.cpp
Student<int> p;
p.a = 10;
Student<char> p1;
p1.a = 100;
cout << "p.a :" << p.a << endl; //输出10
cout << "p1.a :" << p1.a << endl; //输出100 p和p1虽然都是由模板来,但不共享
模板的例子:
#include "stdafx.h"
#include "iostream"
using namespace std;
//1.对象元素必须能够被拷贝 =操作符重载,默认拷贝构造是浅拷贝
//容器是将对象拷贝一份放进去的,而不是将对象本身放进去的
//拷贝中注意 深拷贝 浅拷贝的问题
template <class T>
class MyArray
{
public:
MyArray(int capacity)
{
this->m_Capacity = capacity;
this->m_Size = 0;
m_pArrd = new T[capacity];
}
//拷贝构造
MyArray(const MyArray<T>& array1)
{
this->m_Capacity = array1.m_Capacity;
this->m_Size = array1.m_Size;
this->m_pArrd = new T[array1.m_Capacity];
for (int i = 0; i < array1.m_Size; i++)
{
this->m_pArrd[i] = array1.m_pArrd[i];
}
cout << "拷贝构造" << endl;
}
//[]重载
T& operator [](int index)
{
return this->m_pArrd[index];
}
//等号操作符重载
MyArray<T>& operator =(const MyArray<T>& array1)
{
if (this->m_pArrd != NULL)
{
delete []this->m_pArrd;
}
this->m_Capacity = array1.m_Capacity;
this->m_Size = array1.m_Size;
this->m_pArrd = new T[array1.m_Capacity];
for (int i = 0; i < array1.m_Size; i++)
{
this->m_pArrd[i] = array1.m_pArrd[i];
}
cout << "重载操作符" << endl;
return *this;
}
//对左值取引用
void PushBack(T& var)
{
if (this->m_Size >= this->m_Capacity)
return;
else
{
this->m_pArrd[this->m_Size] = var;
this->m_Size++;
}
}
//对右值取引用(直接可以传数值)
void PushBack(T&& var)
{
if (this->m_Size == this->m_Capacity)
return;
else
{
this->m_pArrd[this->m_Size] = var;
this->m_Size++;
}
}
~MyArray()
{
if (this->m_pArrd != NULL)
delete []this->m_pArrd;
}
private:
int m_Capacity;
int m_Size;
T* m_pArrd;
};
int main()
{
MyArray <int> Array(10);
int a = 1, b = 2, c = 3, d = 4;
Array.PushBack(a);
Array.PushBack(b);
Array.PushBack(c);
Array.PushBack(d);
for (int i = 0; i < 4; i++)
{
cout << Array[i] <<" ";
}
cout << endl;
MyArray <int> Array1(5);
Array1 = Array;// 等号操作符重载
Array1.PushBack(5); //右值作为引用
for (int i = 0; i < 5; i++)
{
cout << Array1[i] << " ";
}
cout << endl;
MyArray <int> Array2=Array1;//拷贝构造
Array2[4] = 5;// []重载
for (int i = 0; i < 5; i++)
{
cout << Array2[i] << " ";
}
cout << endl;
return 0;
}