一、函数模板
1.泛型编程的概念
泛型编程就是不考虑具体数据类型的编程,再C++中通过模板来实现。其和普通编程方式的区别就是类型可以参数化,即其参数是不固定的。语法:template<typename T>,其中 template关键字是告诉编译器要使用泛型编程,typename用来声明泛指类型,即模板中的数据类型可以用T来表示;在模板中,泛指类型T可以代表任何的数据类型,而其代表的具体类型可以通过编译器自动推导,也可以在调用时来指定。
template<typename T
>
void Sort(T a
[], int len
)
{
for(int i
= 0; i
< len
; i
++)
{
for(int j
= i
; j
< len
; j
++)
{
if(a
[i
] > a
[j
])
{
swap(a
[i
], a
[j
]);
}
}
}
}
template<typename T
>
void print(T a
[], int len
)
{
for(int i
= 0; i
< len
; i
++)
{
cout
<< a
[i
] << " ";
}
}
int main()
{
int i
[5] = {3, 1, 2, 4, 5};
print(i
, 5);
Sort(i
, 5);
print
<int>(i
, 5);
string s
[5] = {"aaa", "ccc", "bbb", "ddd", "eee"};
print(s
, 5);
Sort
<string
>(s
, 5);
print(s
, 5);
}
2.函数模板
函数模板是一种特殊的函数,编译器会对其编译两次,第一次对基本语法等进行常规编译,程序中泛指类型T的具体类型在第二次编译时才能确定,因此第二次是对数据的类型参数代替后进行编译。若编译器自动推导时,类型必须严格的匹配,并不会自动进行隐式转换;而若进行显式指定则会进行隐式转换。
class cls{
cls(cls
&s
){};
};
template <typename T
>
void Swap(T
& a
, T
& b
)
{
T c
= a
;
a
= b
;
b
= c
;
}
typedef void(func1
)(int&, int&);
typedef void(func2
)(double&, double&);
typedef void(func3
)(cls
&, cls
&);
int main()
{
func1
* p1
= Swap
;
func2
* p2
= Swap
;
func3
* p3
= Swap
;
cout
<< "p1 = "<< p1
<< endl
;
cout
<< "p2 = "<< p2
<< endl
;
cout
<< "p3 = "<< p3
<< endl
;
}
函数模板可以定义多个不同类型参数,对于多参数模板无法自动推导返回值类型,因此必须显示指定,可以通过从左到右指定类型参数,一般将返回值作为第一个类型参数;
template <typename T1
, typename T2
, typename T3
>
T1
add(T2 a
, T3 b
)
{
return static_cast<T1
>(a
+ b
);
}
int main()
{
int a
= add
<int>(3, 1.5);
double b
= add
<double , int>(3, 5);
double c
= add
<double, int, double>(3.14, 0.618);
cout
<< a
<< endl
;
cout
<< b
<< endl
;
cout
<< c
<< endl
;
}
函数模板也可以被重载,当函数模板与函数重载同时存在时,编译器会优先使用函数重载,但若函数模板效果更好,编译器会选择函数模板;可以通过空参的函数模板强制编译器使用函数模板。
template < typename T
>
T
Max(T a
, T b
)
{
cout
<< "T Max(T a, T b)" << endl
;
return a
> b
? a
: b
;
}
int Max(int a
, int b
)
{
cout
<< "int Max(int a, int b)" << endl
;
return a
> b
? a
: b
;
}
template < typename T
>
T
Max(T a
, T b
, T c
)
{
cout
<< "T Max(T a, T b, T c)" << endl
;
return Max(Max(a
, b
), c
);
}
int main()
{
int a
= 1;
int b
= 2;
cout
<< Max(a
, b
) << endl
;
cout
<< Max
<>(a
, b
) << endl
;
cout
<< Max(3.0, 4.0) << endl
;
cout
<< Max(5.0, 6.0, 7.0) << endl
;
cout
<< Max('a', 100) << endl
;
return 0;
}
二、类模板
1.类模板的概念
类模板的意义 (1)一些类的作用就是用于存储和组织数据元素,而并不关心类中成员的具体数据类型,因此可以通过类模板就可以使得类无需关心成员的具体类型; (2)类模板是以相同的方式处理不同的数据类型,只要关注类所实现的功能就可以。语法 类模板在定义对象时,无法通过自动推导的方式确定类中使用了泛指类型的成员的具体类型,必须通过class<int> obj显式指定来确定。
template <typename T
>
class cls{
public:
T
add(T a
, T b
)
{
return (a
+ b
);
}
};
int main()
{
cls
<int> s1
;
}
2.类模板的使用
函数模板会根据参数类型的不同生成不同的函数,类模板也会根据定义对象时显式指定的类型不同生成不同的类。类模板同函数模板一样,在编译时会进行二次编译,第一次是对基本语法等常规编译,第二次是对参数替换后的类进行编译。在工程应用中,类模板的声明和其中的成员实现必须在同一个文件中,并且在外部实现成员函数时,必须加上模板<>声明。
#ifndef _OPT_H
#define _OPT_H
#include <iostream>
#include <string>
using namespace std
;
template <typename T
>
class cls{
public:
T
add(T a
, T b
);
T
sub(T a
, T b
);
T
mul(T a
, T b
);
T
div(T a
, T b
);
};
template <typename T
>
T cls
<T
> ::add(T a
, T b
)
{
return (a
+ b
);
}
template <typename T
>
T cls
<T
> ::sub(T a
, T b
)
{
return (a
- b
);
}
template <typename T
>
T cls
<T
> ::mul(T a
, T b
)
{
return (a
* b
);
}
template <typename T
>
T cls
<T
> ::div(T a
, T b
)
{
return (a
/ b
);
}
string
operator- (string
& a
, string
& b
)
{
return "overloaded successful!";
}
#endif
#include <iostream>
#include <string>
#include "operator.h"
using namespace std
;
int main()
{
cls
<int> s1
;
cout
<< s1
.add(1, 2) << endl
;
cout
<< s1
.sub(1, 2) << endl
;
cout
<< s1
.mul(1, 2) << endl
;
cout
<< s1
.div(1, 2) << endl
;
cls
<string
> s2
;
cout
<< s2
.sub("abc", "bcd") << endl
;
3.类模板的特化
类模板同函数模板一样,可以定义任意多个泛指类型参数template <typename T1, typename T2>类模板的特化是指,根据不同的类型参数,可以指定类模板的特殊实现,类似于重载。编译器话根据具体的类型来调用不同的特化类模板。类模板的特化分为部分特化template<typename T> class cls<T, T>与完全特化template <> class cls<type, type>,完全特化中已经不含有泛指类型T了。特化的类模板类似于函数的重载,本质是同一个类模板;使用方式都必须显式指定每一个具体类型;
template <typename T1
, typename T2
>
class cls{
public:
void add(T1 a
, T2 b
)
{
cout
<< "类模板" <<" template <typename T1, typename T2>" << endl
;
cout
<< a
+ b
<< endl
;
}
};
template <typename T
>
class cls<T
*, T
*>{
public:
void add(T
* a
, T
* b
)
{
cout
<< "部分特化" <<" template <typename T>" << endl
;
cout
<< *a
+ *b
<< endl
;
}
void other()
{
cout
<< "more" << endl
;
}
};
template < >
class cls<int , int >
{
public:
void add(int a
, int b
)
{
cout
<< "完全特化" <<" template < >" << endl
;
cout
<< a
+ b
<< endl
;
}
};
int main()
{
cls
<int, double> s1
;
s1
.add(1, 2.5);
int a
= 5, b
= 10;
cls
<int*, int*> s2
;
s2
.add(&a
, &b
);
cls
<int, int> s3
;
s3
.add(a
, b
);
return 0;
}
函数模板也支持特化,但只支持完全特化
template <typename T1
, typename T2
>
void func(T1 a
, T2 b
)
{
cout
<< "template <typename T1, typename T2>" << endl
;
cout
<< static_cast<int>(a
+ b
) << endl
;
}
template < >
void func
<int, int>(int a
, int b
)
{
cout
<< "template < >" << endl
;
cout
<< static_cast<int>(a
+ b
) << endl
;
}
void func(int a
, int b
)
{
cout
<< "func" << endl
;
cout
<< static_cast<int>(a
+ b
) << endl
;
}
int main()
{
int a
= 10;
int b
= 15;
double c
= 15;
func(a
, b
);
func
<int, int>(a
, b
);
func
<int, double>(a
, c
);
}
三、类模板的应用
1.智能指针类模板
STL库中的智能指针auto_ptr (1)智能指针本质是类的对象,因此声明周期结束时会自动调用析构函数来销毁指向的内存空间; (2)auto_ptr不能指向堆数组,只能指向堆对象/变量; (3)一片堆空间只属于一个智能指针;
class cls{
public:
cls()
{
cout
<< "cls" << endl
;
}
void print()
{
cout
<< "function" << endl
;
}
~cls()
{
cout
<< "~cls" << endl
;
}
};
int main()
{
auto_ptr
<cls
> s1(new cls
);
s1
->print();
cout
<< s1
.get() << endl
;
cout
<< endl
;
auto_ptr
<cls
> s2(s1
);
cout
<< s1
.get() << endl
;
cout
<< s2
.get() << endl
;
return 0;
}
2.自己制作智能指针类模板
template<typename T
>
class T{
int a
;
public:
T(){
a
= 0;
}
T(int i
){
a
= i
;
}
int getA()
{
return a
;
}
};
class pointer{
T
*ps
;
public:
pointer(){
ps
= NULL;
}
pointer(const T
* p
){
ps
= const_cast<T
*>(p
);
}
pointer(const pointer
&p
)
{
ps
= p
.ps
;
const_cast<pointer
&>(p
).ps
= NULL;
}
T
& operator *()
{
return *ps
;
}
T
* operator ->()
{
return ps
;
}
T
* getPs()
{
return ps
;
}
~pointer(){
cout
<< "delete" << endl
;
delete ps
;
}
};
int main()
{
pointer
<cls
> p1
= new cls(10);
cout
<< p1
->getA() << endl
;
cout
<< p1
.getPs() << endl
;
pointer
<cls
> p2
= p1
;
cout
<< p1
.getPs() << endl
;
cout
<< p2
.getPs() << endl
;
p2
++;
}
2.单例类模板
单例模式就是只能定义一个对象的类
class cls{
static cls
* mp
;
cls(const cls
& s
);
cls
& operator=(const cls
* s
);
cls(){};
public:
static cls
* func();
void getMp()
{
cout
<< "mp = " << mp
<< endl
;
}
};
cls
* cls
::mp
= NULL;
cls
* cls
::func(){
if(mp
== NULL)
{
mp
= new cls
;
}
return mp
;
}
int main()
{
cls
*s1
= cls
::func();
s1
->getMp();
cls
*s2
= cls
::func();
s2
->getMp();
cls
*s3
= cls
::func();
s3
->getMp();
return 0;
}
若多个类都需要单例模式,则可以创建单例类模板
template<typename T
>
class cls{
static T
* mp
;
public:
static T
* func();
};
template<typename T
>
T
* cls
<T
>::mp
= NULL;
template<typename T
>
T
* cls
<T
>::func(){
if(mp
== NULL)
{
mp
= new T
;
}
return mp
;
}
#endif
#include <iostream>
#include <string>
#include <memory>
#include "operator.h"
using namespace std
;
class cls1{
friend class cls<cls1
>;
public:
void getMp(){
cout
<< "this = "<< this;
}
};
int main()
{
cls1
*s1
= cls
<cls1
>::func();
s1
->getMp();
return 0;
}