C++学习
八、模板
1、类型模板1-模板函数
例36、template(1)
假如我现在想实现简单的加法运算,那么就要考虑数据的类型。先考虑只有两种情况:整数的和小数的。
于是就可以确定案例函数有add(1, 2)和add(1.1, 2.3),如下
#include <stdio.h>
#include <iostream>
using namespace std;
int add(int a, int b)
{
return a+b;
}
double add(double a, double b)
{
return a+b;
}
int main()
{
cout<< add(1, 2) <<endl;
cout<< add(1.1, 2.3) <<endl;
}
执行结果
@ubuntu:/mnt/hgfs/ub2$ g++ template1.cpp
@ubuntu:/mnt/hgfs/ub2$ ./a.out
3
3.4
@ubuntu:/mnt/hgfs/ub2$
然后就发现这个add()函数只是类型不同,实现方式都是一样。这时候模板的妙处就展现出来了。
如下
#include <stdio.h>
#include <iostream>
using namespace std;
template<typename XXX>
XXX add(XXX a, XXX b)
{
return a+b;
}
int main()
{
cout<< add(1, 2) <<endl;
cout<< add(1.1, 2.3) <<endl;
}
执行结果一样
@ubuntu:/mnt/hgfs/ub2$ g++ template2.cpp
@ubuntu:/mnt/hgfs/ub2$ ./a.out
3
3.4
@ubuntu:/mnt/hgfs/ub2$
2、类型模板2-模板类
例37、template(2)
回顾之前的例11 、例23 、例25 的arr.h
#ifndef _ARR_
#define _ARR_
class ARR{
public:
ARR():tail(0){
}
void addtail(int data);
void show(void);
private:
int data[100];
int tail;
};
#endif
发现私有成员data[100] 的数据类型是固定死了的(int),后面凡是数据都得整型int处理,比如3.7就会当成3,使数据出错。为了变得通用,就可以使用模板来处理,从而灵活运用。案例如下
arr.h
#ifndef _ARR_
#define _ARR_
template <typename XXX>
class ARR{
public:
ARR():tail(0){
}
void addtail(XXX data);
void show(void);
private:
XXX data[100];
int tail;
};
#endif
arr.cpp
#include "arr.h"
#include <stdio.h>
#include <iostream>
using namespace std;
template <typename XXX>
void ARR<XXX>::addtail(XXX data)
{
this->data[tail++] = data;
}
template <typename XXX>
void ARR<XXX>::show(void)
{
int i = 0;
for(; i<tail; i++)
cout<< data[i] << ',';
cout << endl;
}
main.cpp
#include "arr.h"
int main()
{
ARR<int> arr;
arr.addtail(1);
arr.addtail(3);
arr.addtail(6);
arr.addtail(9);
arr.show();
}
运行结果
@ubuntu:/mnt/hgfs/ub2/ARR1$ ls
arr.cpp arr.h main.cpp
@ubuntu:/mnt/hgfs/ub2/ARR1$ g++ *.cpp
/tmp/ccm4VpzB.o: In function `main':
main.cpp:(.text+0x39): undefined reference to `ARR<int>::addtail(int)'
main.cpp:(.text+0x4d): undefined reference to `ARR<int>::addtail(int)'
main.cpp:(.text+0x61): undefined reference to `ARR<int>::addtail(int)'
main.cpp:(.text+0x75): undefined reference to `ARR<int>::addtail(int)'
main.cpp:(.text+0x84): undefined reference to `ARR<int>::show()'
collect2: error: ld returned 1 exit status
@ubuntu:/mnt/hgfs/ub2/ARR1$
出现这个问题是因为在C++中不支持模板分两部分来写(arr.c 和arr.h )
所以需要把这两个整合到一块去(整合到arr.h 中),成如下的arr.h
#ifndef _ARR_
#define _ARR_
#include <iostream>
using namespace std;
template <typename XXX>
class ARR{
public:
ARR():tail(0){
}
void addtail(XXX data);
void show(void);
private:
XXX data[100];
int tail;
};
template <typename XXX>
void ARR<XXX>::addtail(XXX data)
{
this->data[tail++] = data;
}
template <typename XXX>
void ARR<XXX>::show(void)
{
int i = 0;
for(; i<tail; i++)
cout<< data[i] << ',';
cout << endl;
}
#endif
main.cpp 保持之前那样
#include "arr.h"
int main()
{
ARR<int> arr;
arr.addtail(1);
arr.addtail(3);
arr.addtail(6);
arr.addtail(9);
arr.show();
}
运行结果
@ubuntu:/mnt/hgfs/ub2/ARR2$ ls
a.out arr.h main.cpp
@ubuntu:/mnt/hgfs/ub2/ARR2$ g++ main.cpp
@ubuntu:/mnt/hgfs/ub2/ARR2$ ./a.out
1,3,6,9,
@ubuntu:/mnt/hgfs/ub2/ARR2$
然后假设我添加的是浮点数,可以改写如下
#include "arr.h"
int main()
{
#if 0
ARR<int> arr;
arr.addtail(1);
arr.addtail(3);
arr.addtail(6);
arr.addtail(9);
#endif
ARR<double> arr;
arr.addtail(1.7);
arr.addtail(3.5);
arr.addtail(6.8);
arr.addtail(9.6);
arr.show();
}
执行结果依然没问题
@ubuntu:/mnt/hgfs/ub2/ARR2$ ls
a.out arr.h main.cpp
@ubuntu:/mnt/hgfs/ub2/ARR2$ g++ main.cpp
@ubuntu:/mnt/hgfs/ub2/ARR2$ ./a.out
1.7,3.5,6.8,9.6,
@ubuntu:/mnt/hgfs/ub2/ARR2$
这就是模板的魅力!!!
3、非类型模板
template <class T, int SIZE>
class List{
public:
List();
~List();
private:
T arr[SIZE];
int num;
};
例38、template(3)
参照例37,把数组大小也变为模板方式
arr.h
#ifndef _ARR_
#define _ARR_
#include <iostream>
using namespace std;
template <typename XXX, int SIZE>
class ARR{
public:
ARR():tail(0){
}
void addtail(XXX data);
void show(void);
private:
XXX data[SIZE];
int tail;
};
template <typename XXX, int SIZE>
void ARR<XXX, SIZE>::addtail(XXX data)
{
this->data[tail++] = data;
}
template <typename XXX, int SIZE>
void ARR<XXX, SIZE>::show(void)
{
int i = 0;
for(;i<tail; i++)
cout<< data[i] <<',';
cout<<endl;
}
#endif
main.cpp
#include "arr.h"
int main()
{
ARR<int, 100> arr;//类型为int,size为100
arr.addtail(1);
arr.addtail(3);
arr.addtail(6);
arr.addtail(9);
arr.show();
ARR<double, 1000> arr1;//类型为double,size为1000
arr1.addtail(1.7);
arr1.addtail(3.5);
arr1.addtail(6.8);
arr1.addtail(9.6);
arr1.show();
}
执行结果
@ubuntu:/mnt/hgfs/ub2/ARR3$ ls
a.out arr.h main.cpp
@ubuntu:/mnt/hgfs/ub2/ARR3$ g++ main.cpp
@ubuntu:/mnt/hgfs/ub2/ARR3$ ./a.out
1,3,6,9,
1.7,3.5,6.8,9.6,
@ubuntu:/mnt/hgfs/ub2/ARR3$
4、特化
特化
template <>
class List{
public:
List();
~List();
private:
int arr[100];
int num;
};
偏特化
template <class A, class B>
class C{
public:
A a;
B b;
};
/*********************************/
class C<int, B>{
//特化B为int 类型,至于A什么类型并没有没有特化,这种有针对的特化就是偏特化
};
例39、template(4)
在例36中我们已经实现int类型和double类型公用的模板,但现在遇到个判断真假的逻辑加法运算需求(全真才为真,否则为假)。
然后发现这个模板不管用了。
#include <stdio.h>
#include <iostream>
using namespace std;
template<typename XXX>
XXX add(XXX a, XXX b)
{
return a+b;
}
int main()
{
#if 0
cout<< add(1, 2) <<endl;
cout<< add(1.1, 2.3) <<endl;
#endif
cout<< add(true, false) <<endl;
cout<< add(true, true) <<endl;
}
运行结果
@ubuntu:/mnt/hgfs/ub2$ g++ template3.cpp
@ubuntu:/mnt/hgfs/ub2$ ./a.out
1
@ubuntu:/mnt/hgfs/ub2$
根据需求,一真一假结果为假即为0,而这里是1,所以是错误的。于是我们可以使用特化来解决此问题。
#include <stdio.h>
#include <iostream>
using namespace std;
template<typename XXX>
XXX add(XXX a, XXX b)
{
return a+b;
}
template <>
bool add(bool a, bool b)
{
if(a == true && b == true)
return true;
return false;
}
int main()
{
#if 0
cout<< add(1, 2) <<endl;
cout<< add(1.1, 2.3) <<endl;
#endif
cout<< add(true, false) <<endl;
cout<< add(true, true) <<endl;
}
运行结果
@ubuntu:/mnt/hgfs/ub2$ g++ template3.cpp
@ubuntu:/mnt/hgfs/ub2$ ./a.out
0
1
@ubuntu:/mnt/hgfs/ub2$