一、数据指针
#include <iostream>
struct MyStruct
{
int key;
int value;
};
int sum(MyStruct* objs, int MyStruct::* pm, int count)
{
int result = 0;
for(int i = 0; i < count; ++i)
result += objs[i].*pm;
return result;
}
int main(void)
{
MyStruct me[10] =
{
{1,2},{3,4},{5,6},{7,8},{9,10},{11,12},{13,14},{15,16},{17,18},{19,20}
};
//计算10个MyStruct结构的value成员的总和: sum_value 值 为 110 (2+4+6+8++20)
int sum_value = sum(me, &MyStruct::value, 10);
std::cout << "sum_value=" << sum_value << std::endl;
//计算10个MyStruct结构的key成员的总和: sum_key 值 为 100 (1+3+5+7++19)
int sum_key = sum(me, &MyStruct::key, 10);
std::cout << "sum_key=" << sum_key << std::endl;
return 0;
}
说明:
int MyStruct::* pm,pm指向MyStruct中的任一数据成员。 要求MyStruct中的数据成员都是int型。
二、函数指针
#include <iostream>
#include <string>
using namespace std;
typedef unsigned int uint32;
class CNewFuncBase
{
public:
//virtual uint32 CreateNewFunc(void) = 0;
//virtual void DelteNewFunc(uint32 pObj) = 0;
virtual void Update(void) { }
};
typedef CNewFuncBase* (*pfv) ();
typedef void (*pff) (CNewFuncBase*);
pfv g_pfCreateNewFunc = NULL;
pff g_pfDeleteNewFunc = NULL;
CNewFuncBase* g_pObj = NULL;
/*
* 下面是设置具体的功能实例
*/
class CNewFuncInstance : public CNewFuncBase
{
public:
//uint32 CreateNewFunc(void) = 0;
//void DelteNewFunc(uint32 pObj) = 0;
void Update(void) { printf("Update \n"); }
};
CNewFuncBase* CreateNewFunc1(void)
{
CNewFuncBase* pObj = new CNewFuncInstance();
return pObj;
}
void DeleteNewFunc1(CNewFuncBase* pObj)
{
CNewFuncInstance *pInstance = (CNewFuncInstance *)pObj;
delete pInstance;
pObj = 0;
}
int main(void)
{
g_pfCreateNewFunc = CreateNewFunc1;
g_pfDeleteNewFunc = DeleteNewFunc1;
if (g_pfCreateNewFunc != NULL)
{
g_pObj = g_pfCreateNewFunc();
}
if (g_pObj != NULL)
{
g_pObj->Update();
}
if (g_pfDeleteNewFunc != NULL && g_pObj != NULL)
{
g_pfDeleteNewFunc(g_pObj);
}
return 0;
}
说明:实现回调的一种办法,利用派生和虚函数也可以实现回调。
三、成员函数指针(class members)
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
class A
{
public:
A(int v) { value = v; }
void doit() { cout << value << endl; }
static void call_doit(A& rThis)
{
rThis.doit();
}
private:
int value;
};
int main()
{
vector<A> va;
va.push_back(A(1));
va.push_back(A(2));
va.push_back(A(3));
va.push_back(A(4));
//方法1:
//for_each(va.begin(), va.end(), &A::doit); //error
//方法2:
for_each(va.begin(), va.end(), &A::call_doit);
//方法3:
for_each(va.begin(), va.end(), mem_fun_ref<void, A>(&A::doit));
return 0;
}
方法1,编译不能通过。for_each只允许具有一个参数的函数指针或函数对象,哪怕A::doit默认有一个this指针参数也不行。不是for_each没考虑到这一点,而是根本做不到!
方法2,显然是受到了beginthread的启发,使用一个静态函数来转调用,哈哈成功了。但是不爽!这不是C++。
方法3,呼,好不容易啊,终于用mem_fun_ref包装成功了成员函数指针。
似乎方法3不错,又是类型安全的,又可以通用--慢着,首先,它很丑,哪有调用普通C函数指针那么漂亮啊(见方法2),用了一大串包装,又是尖括号又是圆括号,还少不了&号!其次,它只能包装不超过一个参数的函数!尽管它在for_each中够用了,但是你要是想用在超过一个参数的场合,那只有一句话:不可能的任务。
是的,在标准C++中,这是不可能的任务。但事情并不总是悲观的,至少有许多第三方库提供了超越mem_fun的包装。如boost::function等等。但是它也有限制:它所支持的参数仍然是有限的,只有十多个,尽管够你用的了;同样,它也是丑陋的,永远不要想它能够简单的用&来搞定。
也许,以失去美丽的代价,来换取质量上的保证,这也是C++对于函数指针的一种无奈吧……
期待C++0x版本。它通过可变模板参数,能够让mem_fun的参数达到无限个……
四、函数对象
函数对象不是函数指针。但是,在程序代码中,它的调用方式与函数指针一样,后面加个括号就可以了。
函数对象实质上是一个实现了operator()--括号操作符--的类。
可以把附加数据保存在函数对象中,是函数对象的优势所在。
#include <iostream>
class less
{
public:
less(int num) : n(num) {}
bool operator()(int value)
{
return value < n;
}
private:
int n;
};
int main(void)
{
const int SIZE = 5;
int array[SIZE] = { 50, 30, 9, 7, 20};
// 找到小于数组array中小于10的第一个数的位置
int* pa = std::find_if(array, array + SIZE, less(10)); // pa 指向 9 的位置
std::cout << "*pa=" << *pa << std::endl;
// 找到小于数组array中小于40的第一个数的位置
int* pb = std::find_if(array, array + SIZE, less(40)); // pb 指向 30 的位置
std::cout << "*pb=" << *pb << std::endl;
return 0;
}
要想让一个函数既能接受函数指针,也能接受函数对象,最方便的方法就是用模板。
#include <iostream>
/* 统计数组中符合条件的数据个数 */
template<typename FUNC>
int count_n(int* array, int size, FUNC func)
{
int count = 0;
for(int i = 0; i < size; ++i)
if(func(array[i]))
count ++;
return count;
}
class less
{
public:
less(int num) : n(num) {}
bool operator()(int value)
{
return value < n;
}
private:
int n;
};
bool less10(int v)
{
return v < 10;
}
int main(void)
{
const int SIZE = 5;
int array[SIZE] = { 50, 30, 9, 7, 20 };
std::cout << "Using function object: result is " << count_n(array, SIZE, less(10)) << std::endl; // 2
std::cout << "Using function pointer: result is " << count_n(array, SIZE, less10) << std::endl; // 2
return 0;
}
另外,函数对象还有一个函数指针无法匹敌的用法:可以用来封装类成员函数指针!
因为函数对象可以携带附加数据,而成员函数指针缺少一个类实体(类实例)指针来调用,因此,可以把类实体指针给函数对象保存起来,就可以用于调用对应类实体成员函数了。
#include <iostream>
template<typename O>
class memfun
{
public:
memfun(void(O::*f)(const char*), O* o): pFunc(f), pObj(o){}
void operator()(const char* name)
{
(pObj->*pFunc)(name);
}
private:
void(O::*pFunc)(const char*);
O* pObj;
};
class A
{
public:
void doIt(const char* name)
{
std::cout << "Hello " << name << "!" << std::endl;
}
};
int main(void)
{
A a;
memfun<A> call(&A::doIt, &a); // 保存 a::doIt指针以便调用
call("Kitty"); // 输出 Hello Kitty!
return 0;
}
大功告成了,终于可以方便保存成员函数指针,以备调用了。
不过,现实是残酷的。函数对象虽然能够保有存成员函数指针和调用信息,以备象函数指针一样被调用,但是,它的能力有限,一个函数对象定义,最多只能实现一个指定参数数目的成员函数指针。
标准库的mem_fun就是这样的一个函数对象,但是它只能支持0个和1个参数这两种成员函数指针。如 int A::func()或void A::func(int)、int A::func(double)等等,要想再多一个参数如:int A::func(int, double),不好意思,不支持。想要的话,只有我们自已写了。
而且,就算是我们自已写,能写多少个?5个?10个?还是100个(这也太恐怖了)?
好在boost库提供了boost::function类,它默认支持10个参数,最多能支持50个函数参数(多了,一般来说这够用了。但它的实现就是很恐怖的:用模板部份特化及宏定义,弄了几十个模板参数,偏特化(编译期)了几十个函数对象。
----
C++0x已经被接受的一个提案,就是可变模板参数列表。用了这个技术,就不需要偏特化无数个函数对象了,只要一个函数对象模板就可以解决问题了。期待吧。
补充1:使用boost::functon和boost::bind
#include <iostream>
#include <map>
#include <string>
#include <boost/function.hpp>
#include <boost/bind.hpp>
class CSecuTradeHandler
{
public:
void processOrderPost(const std::string& input_param, std::string &result)
{
std::cout << "called processOrderPost()" << std::endl;
}
};
class CBankSecuTransHandler
{
public:
void processBankSecuTrans(const std::string& input_param, std::string &result)
{
std::cout << "called processBankSecuTrans()" << std::endl;
}
};
// typedef void (*ProcessFunction)(const std::string&, std::string&);
typedef boost::function<void(const std::string&, std::string&)> ProcessFunction;
typedef std::map<std::string, ProcessFunction> ProcessMap;
ProcessMap processMap_;
CSecuTradeHandler* pSecuTradeHandler = NULL;
CBankSecuTransHandler* pBankSecuTransHandler = NULL;
bool init()
{
pSecuTradeHandler = new CSecuTradeHandler();
processMap_["order_post"] = boost::bind(&CSecuTradeHandler::processOrderPost, pSecuTradeHandler, _1, _2);
pBankSecuTransHandler = new CBankSecuTransHandler();
processMap_["banksecu_trans"] = boost::bind(&CBankSecuTransHandler::processBankSecuTrans, pBankSecuTransHandler, _1, _2);
return true;
}
bool dispatchCall(const std::string& func_flag, const std::string& input_param, std::string &result)
{
ProcessMap::iterator pfn = processMap_.find(func_flag);
if (pfn == processMap_.end())
{
return false;
}
(pfn->second)(input_param, result);
return true;
}
int main(int argc, char *argv[])
{
init();
std::string input_param = "{[]}";
std::string result;
std::string func_flag = "order_post";
dispatchCall(func_flag, input_param, result);
func_flag = "banksecu_trans";
dispatchCall(func_flag, input_param, result);
return 0;
}
补充2:使用C++11中std::function和std::bind,需要编译器支持。
#include <iostream>
#include <functional>
using namespace std;
class TestClass
{
public:
int ClassMember(int a) { return a; }
static int StaticMember(int a) { return a; }
};
int main()
{
std::function<int(int)> func;
// 类成员函数
TestClass testObj;
func = std::bind(&TestClass::ClassMember, testObj, std::placeholders::_1);
int result = func(40);
cout << "类成员函数:" << result << endl;
// 类静态函数
func = TestClass::StaticMember;
result = func(50);
cout << "类静态函数:" << result << endl;
return 0;
}
参考:http://www.cnblogs.com/ly4cn/