无论是C还是C++,都不允许将一个函数传递给另一个函数,相反,你必须使用函数指针,qsort函数就是这样的一个函数。
void qsort(void* base, size_t nmemb, size_t size, int(*cmpfcn)(const void* a, const void *b));
qsort是按值传递的,C++和C标准都遵循这个原则:函数指针是按值传递的。
for_each是安置传递的,其原型如下:
template<class InputIterator, class Function>
Function
for_each(InputIterator first, InputIterator last, Function f);//按值传递past-by-value
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Dosomething :public unary_function<int, void>{
public:
void operator()(int x){};
};
int main()
{
typedef vector<int>::iterator IntIterator;
vector<int> di;
Dosomething d;//创建一个函数对象
//用类型参数dequeInerator和Dosomething&来调用for_each,这将强制d按照引用传递并返回
for_each<IntIterator, Dosomething&>(di.begin(), di.end(), d);
return 0;
}
但是STL的使用者几乎从来不会做这样的事情,而且,如果将函数对象按照引用传递,有些算法是不能编译通过的。因此,假设函数独享总是按值传递,在实践中,这种假设几乎总是成立的。
因此这意味着两件事情:
1、函数必须尽量小。
2、函数对象必须是单态的,也就是说,他们不能使用虚函数。
这是因为,如果参数的类型是基类类型,而参数类型确实派生类类型,那么在传递的过程中会产生剥离问题:在对象被复制过程中,派生部分可能会被去掉,而仅仅保留基类部分。
解决方法:
将所需的数据和虚函数从函数子类中分离出来,放到一个新的类中,然后在函数子类中包含一个指针,指向这个新类的对象,例如:如果你希望创建一个包含大量数据并且使用多态性的含数子类:
template<typename T>
class BPFC :public unary_function<T, void>{//BPFC=big polymorphic Function class
private:
float a;
int x;
public:
virtual void operator()(const T& val)const;//这是一个虚函数,所以存在剥离问题
};
那么就应该创建一个小巧的、单态的类,其中包含一个指针,指向一个实现类,并且将所有的数据和虚函数都放在实现类中:
template<typename T>
class BPFCImpl :public unary_function<T, void>{
private:
float a;//原来BPFC中的数据
int x;
virtual ~BPFCImpl();//多态类需要虚析构函数
virtual void operator()(const T& val)conat;
friend class BPFC<T>;//允许BPFC访问内部数据
};
template<typename T>
class BPFC :public unary_function<T, void>{
private:
BPFCImpl<T> *pImpl;
public:
void operator()(const T& val)const
{
pImpl->operator()(val);
}
};
从STL的角度看,需要牢记的是,如果函数子类用到了这项技术,那么它必须以某种合理的方式来支持拷贝动作,如果你是上述BPFC类的作者,那么你必须确保BPFC的拷贝函数正确处理了它所指向的BPFCImpl对象,也许最简单而合理的做法是使用引用计数,可以使用类似于BOOST的shared_ptr这样的辅助类。