类模板中重载的():
()的重载很特殊,因为如果一个类重载了()那么该类的对象就称为函数对象。也就是这个类的对象可以作为函数被调用或者作为函数指针传入其他函数。我们在重载()时一定要根据他所在位置的作用来判断他的返回类型以及函数体、参数!!!
1.首先是区别模板类是在建立对象还是在调用经重载的()函数:
也许这个标题很迷,但是我这个小白在做题时确实被搞糊涂了。。。不过()的重载确实经常用到,在这里总结一下。
首先说个大致形式:
如果在类模板中有()的重载函数:函数返回值类型 operator ()(形参){ }
。在main中如果是:类名<数据类型> ( ) (传入的实参);
那么就是在调用重载的()函数,如果是类名<数据类型> (传入的实参);
那么就是在定义对象并调用构造函数。因为会有好多括号容易有些懵逼,看两道最近做的程序填空题:
第一题是调用重载的()函数:
/*
编写GoodCopy类模板,使得程序按指定方式输出
输入:
第一行是整数 t,表示数据组数
每组数据:
第一行是整数 n , n < 50
第二行是 n 个整数
第三行是 n 个字符串
输出;
将输入的整数原序输出两次,用","分隔
然后将输入的字符串原序输出两次,也用 ","分隔
样例输入
2
4
1 2 3 4
Tom Jack Marry Peking
样例输出
1,2,3,4,
1,2,3,4,
Tom,Jack,Marry,Peking,
Tom,Jack,Marry,Peking,
*/
#include <iostream>
using namespace std;
template <class T>
struct GoodCopy {
//补充你的代码
};
int a[200];
int b[200];
string c[200];
string d[200];
template <class T>
void Print(T s,T e) {
for(; s != e; ++s)
cout << * s << ",";
cout << endl;
}
int main()
{
int t;
cin >> t;
while( t -- ) {
int m ;
cin >> m;
for(int i = 0;i < m; ++i) cin >> a[i];
GoodCopy<int>()(a,a+m,b);
Print(b,b+m);
GoodCopy<int>()(a,a+m,a+m/2);
Print(a+m/2,a+m/2 + m);
for(int i = 0;i < m; ++i) cin >> c[i];
GoodCopy<string>()(c,c+m,d);
Print(c,c+m);
GoodCopy<string>()(c,c+m,c+m/2);
Print(c+m/2,c+m/2 + m);
}
return 0;
}
我们可以看出这就是再让我们实现 GoodCopy类模板,而 GoodCopy在main中的作用就是把一个区间内的数据传给另一个容器,另外的a,a+m,a+m/2和c,c+m,c+m/2就是关于指针的移动了在这里不是重点。
补充的代码是:
//your code starts here
void operator()(T* s,T* e,T* x)
{
bool backward = false;
T * tmp;
for(tmp = s;tmp!= e; ++tmp) {
if( tmp == x ) {
backward = true;
break;
}
}
if( !backward) {
for(; s != e; ++s,++x)
* x = * s;
}
else {
T * p = x;
for(tmp = s; tmp != e; ++tmp,++p);//在main中p就指向了a+m/2+m
--p;//因为e(也就是a+m/2+m)只是临界值不会输出故--得到a+m/2+m-1
T * q = e;
-- q;
for(; q != s; --q, --p)//开始让p从m+m/2~m/2+1获得 q从m~1的值
* p = * q;
*p = * q;//最开始s(a[0])在这传进
}
}
//your code ends here
因为这是程序填空题,不能按自己写的方式去想,而是应该看题目中的GoodCopy<int>()(a,a+m,b);
显然是在调用函数而不是定义对象,所以在类中的()重载的函数的形参一定要是三个,分别对应a,a+m,b
第二题是先定义对象调用构造函数再调用重载的()函数
/*程序填空输出指定结果
输入
多组数据每组数据两行
第一行是两个整数 m 和 n
第二行先是一个整数k ,然后后面跟着k个整数
输出
对每组数据,按原顺序输出第二行的后k个整数中,大于m且小于n的数输出两遍,数据保证一定能找到符合要求的整数
输入样例
2 8
5 1 2 3 4 9
输出样例
3,4,
3,4,
*/
#include <iostream>
#include <vector>
using namespace std;
struct A {
int v;
A() { }
A(int n):v(n) { };
bool operator<(const A & a) const
return v < a.v;
};
//你的代码
template <class T>
void Print(T s,T e)
{
for(;s!=e; ++s)
cout << *s << ",";
cout << endl;
}
template <class T1, class T2,class T3>
T2 Filter( T1 s,T1 e, T2 s2, T3 op)
{
for(;s != e; ++s) {
if( op(*s)) {
* s2 = * s;
++s2;
}
}
return s2;
}
ostream & operator <<(ostream & o,A & a)
{
o << a.v;
return o;
}
vector<int> ia;
vector<A> aa;
int main()
{
int m,n;
while(cin >> m >> n) {
ia.clear();
aa.clear();
int k,tmp;
cin >> k;
for(int i = 0;i < k; ++i) {
cin >> tmp;
ia.push_back(tmp);
aa.push_back(tmp);
}
vector<int> ib(k);
vector<A> ab(k);
vector<int>::iterator p = Filter(ia.begin(),ia.end(),ib.begin(),FilterClass<int>(m,n));
Print(ib.begin(),p);
vector<A>::iterator pp=Filter(aa.begin(),aa.end(),ab.begin(),FilterClass<A>(m,n));
Print(ab.begin(),pp);
}
return 0;
}
看main中Filter模板函数的参数要调用的FilterClass是一个类模板形式的,这里就是在定义对象了,所以我们要写构造函数,并且进入Filter模板函数的定义中看看FilterClass类模板的对象如何作用,是 op(*s),也就是作为一个函数被调用,那么这个函数就是()的重载函数。
插入的代码:
//your code starts here
template <class T>
class FilterClass
{
private:
T minV,maxV;
public:
FilterClass(T mi,T ma):minV(mi),maxV(ma) { };
bool operator()(const T & v) const {//就是op()
return minV < v && v < maxV;
}
};
//your code ends here
2.函数对象作为函数指针传入其他函数
先看一个例子(对比第一点中的两个例子,会有更多心得):
/*程序填空,输出指定结果
输入
多组数据,每组一行,是一个整数n和一个字符串s
输出
定义两个整数的距离为两个整数差的绝对值
定义两个字符串的距离为两个字符串长度差的绝对值
对每组数据:
对数组a按和n的距离从小到大排序后输出。距离相同的,值小的排在前面。
然后对数组b,按照和s的距离从小到大输出。距离相同的,字典序小的排在前面
样例输入:
2 a123456
样例输出:
1,3,0,4,7,8,9,10,15,20,
American,Peking,123456789,Jack,To,abcdefghijklmnop,
*/
#include <iostream>
#include <cmath>
#include <algorithm>
#include <string>
using namespace std;
template <class T1,class T2>
struct Closer {
//填入你的代码
};
int Distance1(int n1,int n2) {return abs(n1-n2);}
int Distance2(const string & s1, const string & s2){return abs((int)s1.length()- (int) s2.length());}
int a[10] = { 0,3,1,4,7,9,20,8,10,15};
string b[6] = {"American","Jack","To","Peking","abcdefghijklmnop","123456789"};
int main()
{
int n;string s;
while( cin >> n >> s ) {
sort(a,a+10,Closer<int ,int (*)(int ,int)> (n,Distance1));
for(int i = 0;i < 10; ++i) cout << a[i] << "," ;
cout << endl;
sort(b,b+6,Closer<string,int (*)(const string &,const string & )> (s,Distance2));
for(int i = 0;i < 6; ++i) cout << b[i] << "," ;
cout << endl;
}
return 0;
}
可以看出Closer类作为sort函数的第三个参数,也就是排序的规则函数,而被调用的显然是Closer这个类的对象,而不是直接调用()的重载函数,所以我们在构造Closer类时一定要让n和distance为数据成员,重载()的参数是比较的内容而不是用于比较的函数(distance),这样才符合。
填入的代码:
struct Closer {
// 在此处补充你的代码
T1 n;
T2 op;
Closer(T1 m,T2 dis):n(m),op(dis) {}
bool operator () (const T1 & v1,const T1 & v2){
if(op(v1,n)!=op(v2,n)){
return op(v1,n)<op(v2,n);
}else{
return v1<v2;
}
}
};