模板
C++提供了模板(template)编程的概念。所谓模板,实际上是建立一个通用函数或类, 其类内部的类型和函数的形参类型不具体指定 ,用一个虚拟的类型来代表。这种通用的方式称为模板。 模板是泛型编程的基础, 泛型编程即以一种独立于任何特定类型的方式编写代码如: vector
函数模板(可以嵌套使用)
模板函数就是函数模板的自动实现
功能:使用函数体相同的函数都可以用这个模板替代实现多个函数用来返回两个数的最大值,要求能支持 char 类型、int 类型、doubletemplate <typename T>如:template <typename T>//这里的类属参数 T在下面函数体的 参数中必须出现一次
T Max(T a, T b) {
return a > b ? a : b;
}形式:cout << Max(a, b) << endl;//编译器自动推导类型
cout << Max<int>(a,b)<<endl;//显示类型调用
#include <iostream>
using namespace std;
template <typename T>
T Max(T a, T b) {
return a > b ? a : b;
}
int main(void) {
int a = 4;
int b = 5;
float x = 1.2f;
float y = 2.6f;
cout << Max(a, b) << endl;//编译器自动推导类型
cout << Max<int>(a,b)<<endl;//显示类型调用
cout << Max(x, y) << endl;
return 0;
}
函数模板和函数重载
//当函数模板和普通函数都符合调用时,优先选择普通函数//Max(a,b);//如果 显式指定类型 的使用函数模板,则使用<> 类型列表//Max<>(a, b);//如果函数模板会产生更好的匹配,使用函数模板
函数模板的调用机制
函数模板在调用的时候,会根据调用者的数据类型,创建一个匹配的函数
类模板
类模板和函数模板一致
在类使用数据类型的地方都可以用模板的类属参数进行替换
(成员数据的数据类型,构造函数的参数类型,成员函数的返回值类型)
注:在模板类定义对象的时候必须指定为显示指定类型<>
当为单个参数时:
#include <iostream>
using namespace std;
template <typename T>
class A {
public:
A(T a) {
this->a = a;
}
T getA() {
return a;
}
private:
T a;
};
int main(void) {
A<int> aa(666);
cout << aa.getA() << endl;
return 0;
}
当为多个参数时
#include <iostream>
using namespace std;
template <typename T1,typename T2>
class A {
private:
T1 a;
T2 b;
public:
A(T1 a ,T2 b) {
this->a = a;
this->b = b;
}
T1 getA() {
return a;
}
T2 getB() {
return b;
}
};
int main(void) {
A<int, double> aa(12,4.5);
cout << aa.getA() << endl;
cout << aa.getB() << endl;
return 0;
}
当类作为函数参数的时候
double add(A<int, double>& a) {
double sum = 0;
sum = a.getA() + a.getB();
return sum;
}
当子类继承父类(父类为模板类时)
class B :public A<int, double> {
B(int a, double b):A(a,b) {}
};
当子类是模板类,父类是一般类时
和普通继承一样
#include <iostream>
using namespace std;
class B {
protected:
int a;
double b;
public:
B(int a=1, double b=1.2) {
this->a = a;
this->b = b;
}
};
template <typename T1, typename T2>
class A :public B{
public:
A();
A(T1 a, T2 b) :B(a, b) {}
T1 getA() {
return a;
}
T2 getB() {
return b;
}
};
double add(A<int, double>& a) {
double sum = 0;
sum = a.getA() + a.getB();
return sum;
}
int main(void) {
A<int ,double> aa(12,12.2);
cout << aa.getA() << endl;
cout << aa.getB() << endl;
return 0;
}
当子类和父类都是模板类
和普通继承一样
#include <iostream>
using namespace std;
template <typename T1, typename T2>
class B {
public:
B(T1 a, T2 b){
this->a = a;
this->b = b;
}
T1 getA() {
return a;
}
T2 getB() {
return b;
}
protected:
T1 a;
T2 b;
};
template <typename T1, typename T2>
class A :public B<int, double>{
public:
A();
A(T1 a, T2 b) :B(a, b) {}
T1 getA() {
return a;
}
T2 getB() {
return b;
}
};
double add(A<int, double>& a) {
double sum = 0;
sum = a.getA() + a.getB();
return sum;
}
int main(void) {
A<int, double> aa1(10, 10.2);
cout << aa1.getA() << endl;
cout << aa1.getB() << endl;
A<int ,double> aa(12,12.2);
cout << aa.getA() << endl;
cout << aa.getB() << endl;
return 0;
}
类模板和友元函数
(1) 类内部声明友元函数,必须写成一下形式template < typename T>friend A<T> addA (A<T> &a, A<T> &b);(2) 友元函数实现 必须写成template < typename T>A<T> add(A<T> &a, A<T> &b) {//......}(3) 友元函数调用 必须写成A< int > c4 = addA <int> (c1, c2);
类模板的封装
这里仅分为两个文件(.h和.cpp+main.cpp)
函数前声明 template< 类型形式参数表 >类的成员函数前的 类限定域说明必须要带上虚拟参数列表template<typename T1>
A<T1>::A(T1 a)
{
this->a = a;
}返回的变量是模板类的对象时必须带上虚拟参数列表T1 A<T1>::getA() {
return a;
}成员函数参数中出现模板类的对象时必须带上虚拟参数列表(也可以不带)A<T1> A<T1>::operator+( const A<T1> & other)
{
A<T1> tmp = this->a + other.a;
return tmp.a;
}成员函数内部没有限定( 可带可以不带 )A<T1> A<T1>::operator+( const A<T1> & other)
{
A<T1> tmp = this->a + other.a;
return tmp.a;
}
.h
#include <iostream>
using namespace std;
template <typename T1>
class A {
public:
A(T1 a);
T1 getA();
A operator+(const A& other);
void print();
private:
T1 a;
};
.cpp
#include <iostream>
using namespace std;
#include "A.h"
template<typename T1>
A<T1>::A(T1 a)
{
this->a = a;
}
template <typename T1>
T1 A<T1>::getA() {
return a;
}
template<typename T1>
A<T1> A<T1>::operator+(const A& other)
{
A tmp = this->a + other.a;
return tmp.a;
}
template<typename T1>
void A<T1>::print()
{
cout << this->a << endl;
}
int main(void) {
A<int> a(12);
A<int> b(11);
A<int> c = a + b;
c.print();
return 0;
}
这里仅分为三个文件(.h 和 .cpp 和 main.cpp)
如果分为这三个文件,那么只包含.h头文件就会报错C++ 类模板“无法解析的外部符号
在封装有三个文件的时候mian.cpp中就不用包含.h头文件了,仅包含.cpp文件即可
#include <iostream>
using namespace std;//#include "A.h"//同时包含两个或者仅包含.h都会报错
#include "A.cpp"int main(void) {
A<int> a(12);
A<int> b(11);
A<int> c = a + b;
c.print();
return 0;
}
类模板的静态成员数据
从类模板实例化的每个模板类有自己的类模板数据成员,该 模板类的所有对象共享一个 static 数据成员和非模板类的 static 数据成员一样, 模板类的 static 数据成员也应该在文件范围定义和初始化static 数据成员也可以使用虚拟类型参数 T
public:
static T1 count;
//初始化静态成员数据
template<typename T1>
T1 A<T1>::count = 66;//通过对象a对静态count赋值后
cout << a.count << endl;
a.count = 888;
cout << b.count << endl;
b.count = 1000;
cout << a.count << endl;