我们通过具体的例子来理解,假设我们要实现如下需求:
实现函数用来返回两个数的最大值,要求能支持char类型、int类型、double类型变量
我们可以设计出如下函数
int Max(int a, int b)
{
return a>b ? a:b;
}
char Max(char a, char b)
{
return a>b ? a:b;
}
float Max(float a, float b)
{
return a>b ? a:b;
}
但其中存在许多重复的地方,除了数据类型其他地方一模一样,效率就显得很低下。
为了提高开发效率,于是有了泛型编程,我们用函数模版来实现开始的需求,如下
template
T Max(T a, T b){
return a>b ? a:b;
}
其中T可以是任意的数据类型,极大提高了开发效率
函数模版由以下三部分组成: 模板说明 + 函数定义 + 函数模板调用
template < 类型形式参数表 >
类型 函数名 (形式参数表)
{
//语句序列
}
注意点:不同对象的T类型只能是同一种数据类型
#include
using namespace std;
template
void add(T a, T b) {
cout << a + b << endl;
cout << "调用了模板版本的add()" << endl;
}
void add(int a, int b) {
cout << a + b << endl;
cout << "调用了int版本的add()" << endl;
}
int main() {
int a = 1, b = 4;
double c = 2.5, d = 3.14;
add(a, b);
add(a, b);
return 0;
}
如上所示,如果有普通函数匹配上了具体的数据类型,则会调用普通重载函数,但若在函数名后加上数据类型如
注意:
1. 编译器并不是把函数模板处理成能够处理任意类型的函数
2. 编译器从函数模板通过具体类型产生不同的函数
template
class A
{
public:
A(T t)
{
this->t = t;
}
T &getT()
{
return t;
}
public:
T t;
};
模板类定义类对象,必须显示指定类型
#include
using namespace std;
template
class A {
public:
A(T a, T b) {
this->a = a;
this->b = b;
cout << "构造函数" << endl;
}
void print() {
cout << "a = " << a << " b = " << b << endl;
}
private:
T a, b;
};
int main() {
int a = 1, b = 4;
double c = 2.5, d = 3.14;
A obj1(a, b);
return 0;
}
父类是模板类,子类是普通类
template
class A {
public:
A(T a, T b) {
this->a = a;
this->b = b;
cout << "构造函数" << endl;
}
private:
T a, b;
};
class B :public A {
};
需要具体指出数据类型
父类是普通类,子类是模板类
class B {
};
template
class A : public B {
public:
A(T a, T b) {
this->a = a;
this->b = b;
cout << "构造函数" << endl;
}
private:
T a, b;
};
和普通类的继承类似
父类和子类都是模板类
template
class A {
public:
A(T a, T b) {
this->a = a;
this->b = b;
cout << "构造函数A" << endl;
}
void print() {
cout << "a=" << a << " b=" << b << endl;
}
protected:
T a, b;
};
template
class B :public A {
public:
B(C c) :A(1, 2) {
this->c = c;
cout << "构造函数B" << endl;
cout << "c=" << c << endl;
cout << "a=" << this->a << " b=" << this->b << endl;
}
private:
C c;
};
子类从模板类继承的时候,需要让编译器知道父类的数据类型具体是什么
#pragma once
#include
using namespace std;
template
class A
{
public:
A(T t = 0);
T& getT();
A operator +(const A& other);
void print();
private:
T t;
};
#include "A.h"
template
void A::print()
{
cout << this->t << endl;
}
template
A::A(T t)
{
this->t = t;
}
template
T& A::getT()
{
return t;
}
template
A A::operator+(const A& other)
{
A tmp;
tmp.t = this->t + other.t;
return tmp;
}
#include
#include"A.h"
#include"A.cpp"
using namespace std;
int main() {
A a(10),b(20);
A c = a + b;
cout << c.getT() << endl;
c.print();
return 0;
}
当我们的类声明文件和实现函数分离时,由于类模板的特殊性,在main函数中我们也要#.cpp头文件,否则系统将找不到实现函数。
注意:
template
A operator+(const A& a, const A& b)
{
A tmp;
tmp.t = a.t + b.t;
return tmp;
cout << "友元函数" << endl;
}
友元函数的调用
int main() {
A a(10),b(20);
A c = a + b;
cout << c.getT() << endl;
c.print();
return 0;
}
静态对象的定义和调用
#include
#include"A.h"
#include"A.cpp"
using namespace std;
template
class C {
public:
static int count;
};
template int C::count = 100;
int main() {
cout << C::count << endl;
return 0;
}
注意:
可以使用多个虚拟类型名,但每个前面都要加上typename
在定义对象时分别代入实际的类型名如:someclass