一.类模板
(1)概念
类模板中定义的函数参数或者属性等数据类型可以参数化
template <typename T,typename U,...>
class 类型
{};
#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, const char *argv[])
{
Test<int,char> t1(1,'a');
t1.show();
return 0;
}
ps:类模板调用一定要显式调用
(2)模板类的继承
#include <iostream>
using namespace std;
template <typename T>
class Parent
{
protected:
T a;
public:
Parent(T a)
{
this->a = a;
}
void show()
{
cout << a << endl;
}
};
class Child:public Parent<int>
{
public:
Child(int a):Parent(a)
{}
void show()
{
cout << a << endl;
}
};
template <typename T,typename U>
class Child2:public Parent<T>
{
private:
U b;
public:
Child2(T a,U b):Parent<T>(a)
{
this->b = b;
}
void show()
{
cout << this->a << " " << this->b << endl;
}
};
int main(int argc, const char *argv[])
{
Child c1(1);
c1.show();
Child2<int,double> c2(1,1.11);
c2.show();
return 0;
}
ps:模板类派生普通类,继承的同时对基类实例化
模板类派生模板类,继承的同时不需要对基类实例化
(3)模板类的声明
#include <iostream>
using namespace std;
template <typename T>
class Test
{
public:
Test(T a);
void show();
~Test();
private:
T a;
};
template <typename T>
Test<T>::Test(T a)
{
this->a = a;
}
template <typename T>
void Test<T>::show()
{
cout << a << endl;
}
template <typename T>
Test<T>::~Test()
{
}
int main(int argc, const char *argv[])
{
Test<int> t1(1);
t1.show();
return 0;
}
(4)模板类中的static
#include <iostream>
using namespace std;
template <typename T>
class Test
{
public:
Test(T a);
void show();
~Test();
private:
T a;
public:
static int count;
};
template <typename T>
int Test<T>::count = 0;
template <typename T>
Test<T>::Test(T a)
{
this->a = a;
count++;
}
template <typename T>
void Test<T>::show()
{
cout << a << endl;
}
template <typename T>
Test<T>::~Test()
{
}
int main(int argc, const char *argv[])
{
Test<int> t1(1);
Test<int> t2(1);
Test<int> t3(1);
Test<int> t4(1);
Test<int> t5(1);
Test<char> t6('a');
Test<char> t7('a');
Test<char> t8('a');
cout << Test<int>::count << endl;
cout << Test<char>::count << endl;
return 0;
}
二.成员模板
2.1为什么要使用成员模板
#include <iostream>
using namespace std;
template <typename T>
class Test
{
public:
T m_a;
public:
void print(const Test<T> &a)
{
cout << a.m_a << endl;
}
};
int main(int argc, const char *argv[])
{
Test<int> a;
a.m_a = 1;
Test<double> b;
b.m_a = 1.123;
a.print(a);
a.print(b);
return 0;
}
报错无法运行
2.2成员模板的实现
#include <iostream>
using namespace std;
template <typename T>
class Test
{
public:
T m_a;
public:
template <typename X>
void print(const Test<X> &a)
{
cout << a.m_a << endl;
}
};
int main(int argc, const char *argv[])
{
Test<int> a;
a.m_a = 1;
Test<double> b;
b.m_a = 1.123;
a.print(a);
a.print(b);
return 0;
}
三.关键词-typename
3.1内嵌依赖类型名
内嵌:是指在类的内部定义的
依赖:依赖于某一个模板参数
类型名:最终要指出的这个类型名
3.2实例
#include <iostream>
using namespace std;
template <typename T>
class Test
{
public:
T m_a;
typedef T* PT;
public:
template <typename X>
void print(const Test<X> &a)
{
cout << a.m_a << endl;
}
};
int main(int argc, const char *argv[])
{
int num = 100;
Test<int>::PT p = #
return 0;
}
四.using给模板起别名
#include <iostream>
using namespace std;
template <typename T,typename U>
class Test
{
public:
T m_a;
typedef T* PT;
public:
};
template <typename S>
using MyA = Test<string,S>;
using s32 = int;
using P_func = void(*)(int,int);
int main(int argc, const char *argv[])
{
Test<string,int> a;
MyA<int> a2;
return 0;
}
五.实例化
5.1 #pragma once
1.ifndef方法是c/c++的标准支持,比较常用的方式
#pragma once 一般由编译器提供保证,功能是保证同一个文件不会被包含多次
visual studio 2017之后的版本新建的头文件都会自带#pragma once
2.兼容性:#pragma once产生于ifndef之后,ifndef不受任何编译器的限制,而#pragma once方法有些编译器不支持,兼容性不够好
3.ifndef可以针对文件中的一部分代码,而#pragma once只针对整个文件
4.ifndef更加灵活,兼容性好,#pragma once操作简单,效率更高
5.2隐式实例化
隐式实例化是指在函数调用的时候,如果没有发现与之相匹配的函数存在,编译器会寻找同名的函数模板,如果可以成功进行参数的推演,就对函数模板实例化
类模板同上。
5.3显示实例化
显式实例化:外部实例化,在不发生函数调用的时候将函数模板实例化
类模板同上
5.3.1函数模板的显式实例化
template[返回值类型][函数名]<实际类型列表>(函数参数列表)
template void func<int>(const int&);
5.3.2类模板的显式实例化
template class Test<int>;
作用:减少隐式实例化多个函数和类的开销,只实例化一次(不同编译器处理机制可能不同)
#include <string>
using namespace std;
class A
{
public:
A()
{}
int m_a;
};
template <typename T,typename U>
class Test
{
public:
T m_a;
U m_b;
public:
void print()
{
cout << m_a << endl;
cout << m_b << endl;
}
};
template <>
class Test<A,string>
{
public:
A m_a;
string m_b;
public:
void print()
{
cout << "class Test<A,string>" << endl;
cout << m_a.m_a << endl;
cout << m_b << endl;
}
};
int main(int argc, const char *argv[])
{
Test<int,string> a;
a.m_a = 1;
a.m_b = "helloworld";
a.print();
A tb;
Test<A,string> s1;
s1.m_a = tb;
s1.m_b = "world";
s1.print();
return 0;
}
(2)类模板的偏特化
#include <string>
using namespace std;
class A
{
public:
A()
{}
int m_a;
};
template <typename T,typename U>
class Test
{
public:
T m_a;
U m_b;
public:
void print()
{
cout << m_a << endl;
cout << m_b << endl;
}
};
template <typename T>
class Test<T,string>
{
public:
T m_a;
string m_b;
public:
void print()
{
cout << "class Test<T,string>" << endl;
cout << m_a << endl;
cout << "name:" << m_b << endl;
}
};
int main(int argc, const char *argv[])
{
Test<int,string> a;
a.m_a = 1;
a.m_b = "helloworld";
a.print();
return 0;
}
(3)类模板参数范围偏特化
#include <string>
using namespace std;
class A
{
public:
A()
{}
int m_a;
};
template <typename T,typename U>
class Test
{
public:
T m_a;
U m_b;
public:
void print()
{
cout << m_a << endl;
cout << m_b << endl;
}
};
template <typename T,typename U>
class Test<const T,const U>
{
public:
T m_a;
U m_b;
public:
void print()
{
cout << "class Test<const T,const U>" << endl;
}
};
int main(int argc, const char *argv[])
{
Test<const int,const int> a1;
a1.print();
return 0;
}