您的位置:首页 > 其它

STL — 仿函数的实现原理和应用

2017-04-19 08:33 176 查看

STL仿函数

                                                                                                      

今天我们来看看一个比较冷门但是很有趣的知识->仿函数,听名字我们就知道,他肯定是让一个不是函数的东西拥有函

数的功能,跟我们之前说的智能指针很类似,那么我们就有理由想到->类,没有错这就是类。这就是面向对象的优点之

处,以前我体会不到面向对象的好处,现在越学越觉得有用。

可不要小看这个仿函数,他可是STL六大组件之一拥有成堆的应用场景以及应用技巧.让我们先来明白一个它最简单的使

用.这个概念,说的通俗点就是在一个类中利用运算符重载重载"()"让类拥有函数的使用特性和功能.仿函数在C语言和

C++中都可以实现,C语言中的仿函数是使用函数指针和回调函数实现的。

我们先来看看一个C语言中的实现:

#include <stdio.h>
#include <stdlib.h>
//int sort_function( const void *a, const void *b);
int sort_function( const void *a, const void *b)
{
return *(int*)a-*(int*)b;
}

int main()
{

int list[5] = { 54, 21, 11, 67, 22 };
qsort((void *)list, 5, sizeof(list[0]), sort_function);//起始地址,个数,元素大小,回调函数
int  x;
for (x = 0; x < 5; x++)
printf("%i\n", list[x]);

return 0;
}


然后C++就简单多了,具体调用举个例子我们实现一个判断是否相等的仿函数:

template<class T>
struct A
{
bool operator()(const T& a,const T& b)
{
return (a == b);
}
};

int main()
{
A<int>a;
cout << a(1, 2) << endl;
system("pause");
return 0;
}


这就是一个最简单的仿函数了,大家大致应该明白这个仿函数怎么用了吧。现在我对它进行稍微复杂一点的应用,我们

在智能指针中实现过shared_ptr的简单实现,现在我们看看代码:

template<class T>
class shared
{
public:
shared(T* ptr)
:_ptr(ptr)
, _num(new int(1))
{
}
shared(const shared<T>& ap)
:_ptr(ap._ptr)
, _num(ap._num)
{
++(*_num);
}
shared<T>& operator=(const shared<T>& ap)
{
if (_ptr != ap._ptr)
{
Release();
_ptr = ap._ptr;
_num = ap._num;
++(*_num);
}
return *this;
}
T* operator->()
{
return _ptr;
}

T& operator*()
{
return *_ptr;
}
void Release()
{
if (0 == (--*_num))
{
cout << "智能指针爸爸帮你释放空间了" << endl;
delete _ptr;
delete _num;
_ptr = NULL;
_num = NULL;
}
}
~shared()
{
Release();
}
protected:
T* _ptr;
int* _num;
};


但是里面有一个问题就是,我们无论用智能指针指向任何对象它最后都是用delete释放,这个显然是不可以的。因为开

辟空间不仅仅只有new还有new[],malloc。。。。。 所以这个实现有一点简单了,我们现在运用仿函数尝试一下解决

这个问题。

在这里就需要我们思考了,这个怎么办,我们可以这样想要将模板和仿函数联系起来,因为在释放空间的时候数据(到

底是使用delete还是delete[])是从类外传递进来的,那我们可以事先分别实现内部使用delete释放空间和使用

delete[]释放空间的仿函数,然后把它的类从模板里传进来,然后在目标类内创建对象,然后再调用对象的仿函数。

//使用delete释放空间的仿函数
template<class T>
class Delete
{
public:
Delete()
{}
void operator()(T* _ptr)
{
cout << "delete" << endl;
delete _ptr;
_ptr = NULL;
}
~Delete()
{}
protected:
T* _ptr;
};

//使用delete[]释放空间的仿函数
template<class T>
class DeleteArray
{
public:
DeleteArray()
{}
void operator()(T* _ptr)
{
cout << "delete[]" << endl;
delete[] _ptr;
_ptr = NULL;
}
~DeleteArray()
{}

};


template<class T,class Del = Delete<T>>

class shared
{};

那么模板就可以设计成这样,让模板的默认属性为delete释放空间,然后把析构函数设计成这样:

inline void Release()
{
if (0 == (--*_num))
{
delete _num;
_num = NULL;
Del _del;
_del(_ptr);
}
}
~shared()
{
Release();
}


就是创建一个Del对象,这里我们的Del比如是Delete,那我们的_del(_ptr)的内部,就是用delete释放_ptr,所以我们就

这样把模板和仿函数联系在一起,我画一张图帮我们理解吧;



我们现在慢慢的发现仿函数的用法真的是特别特别的多,也特别的灵活,而我们现在只需要认识他,在它出现的时候知

道这个东西怎么用,平时应用仿函数可能会带给你想象不到的乐趣与便利。

仿函数和模板可以经常在一起搭档,记住,所以他两个你都得学好~

整体代码:

template<class T>
class Delete
{
public:
Delete()
{}
void operator()(T* _ptr)
{
cout << "delete" << endl;
delete _ptr;
_ptr = NULL;
}
~Delete()
{}
protected:
T* _ptr;
};

//使用delete[]释放空间的仿函数
template<class T>
class DeleteArray
{
public:
DeleteArray()
{}
void operator()(T* _ptr)
{
cout << "delete[]" << endl;
delete[] _ptr;
_ptr = NULL;
}
~DeleteArray()
{}

};

template<class T, class Del = Delete<T>>
class Shared_Ptr
{
public:
Shared_Ptr( T* ptr)
:_ptr(ptr)
, _nums(new int(1))
{}

Shared_Ptr(const Shared_Ptr<T>& cur)
:_ptr(cur._ptr)
, _nums(cur._nums)
{
++(*nums);
}

Shared_Ptr<T>& operator = (Shared_Ptr<T>& cur)
{
if (this != &cur)
{
_ptr = cur._ptr;
_nums = cur._nums;
++(*_nums);
}
return *this;
}

T& operator*()
{
return _ptr;
}

T* operator->()
{
return _ptr;
}

~Shared_Ptr()
{
Relese();
}

void Relese()
{
if (--(*_nums) == 0)
{
delete _nums;
Del _del;
_del(_ptr);
_nums = NULL;
_ptr = NULL;
}
}
protected:
T* _ptr;
int* _nums;

};

void Test()
{
Shared_Ptr<int> ptr(new int(1));
Shared_Ptr<string, DeleteArray<string>> ptr2(new string[20]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: