今天看到有人碰到的一个问题与函数指针有关,是个很特殊的问题: C语言写的函数,要在C++的类里面调用,但是C函数有个参数是全局函数指针(callback函数)。貌似 为了代码更加OO化,想将该C函数封装到一个class里面,然后将callback作为参数传入该class,当然原先callback函数对应的功能都要OO化,用class的member function来实现。所以:问有没有将 C++的member function pointer转化为 C的callback函数指针直接使用的方法。
原来的题目在这里: http://topic.csdn.net/u/20090914/16/670b5f08-5d61-49df-b0cd-fe6e33f5d0f4.html?38764
其实:C++的函数指针包括三种: 全局函数指针,类的static函数指针和成员函数指针。前两个几乎没有区别,最后一个与前面两个有本质的区别。是完全不同的类型。C++是强类型的语言,所以使用两类指针时,不能直接赋值。先来看一下他们定义和调用的语法吧:
class C
{
public: int mem_fun(int arg);
static int static_fun(int arg);
};
int global_fun(int arg);
typedef int (C::*Mem_fun)(int arg);
Mem_fun pmf = &C::mem_fun; // &(C::mem_fun) is error
C ci;
(ci.*pmf)(1); // ci.(*pmf)(1) error; (ci.(*pmf))(1) error;
typedef int (*C_Fun)(int arg);
C_Fun p_static_fun = &C::static_fun;
C_Fun p_global_fun = &global_fun;
C++的member function pointer调用时,需要依赖具体的对象(或指针);而全局函数和类的static函数指针是可以直接调用的,两种指针的基类型完全不同,调用需要的参数也不同,不能转化。
贴一下STL的 mem_fun_t 和 mem_fun_ref_t 的实现:
template <class _Ret, class _Tp>
class mem_fun_t : public unary_function<_Tp*,_Ret>
{
public:
explicit mem_fun_t(_Ret (_Tp::*__pf)())
:_M_f(__pf)
{
}
_Ret operator()(_Tp* __p) const
{
return (__p->*_M_f)();
}
private:
_Ret (_Tp::*_M_f)();
};
template <class _Ret, class _Tp>
class mem_fun_ref_t : public unary_function<_Tp,_Ret>
{
public:
explicit mem_fun_ref_t(_Ret (_Tp::*__pf)())
: _M_f(__pf)
{
}
_Ret operator()(_Tp& __r) const
{
return (__r.*_M_f)();
}
private:
_Ret (_Tp::*_M_f)();
};
这两个class 是成员函数指针的adapter, 方便泛型算法的调用。从 operator ()的实现中可以明确看出 member function pointer 的使用方法。
我给出了一个template的方式,将每个 callback的实现 写成类的static函数,且static函数名称固定。
然后封装C函数的那个类,需要一个template 参数,具体调用C函数的时候的地方,根据template 参数,调用Type::Callback。
代码如下:
#include <iostream>
int sql_exec(const char * sql, int (*callback)(int *))
{
std::cout << "sql_exec" << std::endl;
callback(0);
}
class SqlParser
{
public:
static int Callback(int * p)
{
std::cout << "sqlParser::callback" << std::endl;
}
};
class AddressParser
{
public:
static int Callback(int * p)
{
std::cout << "AddressParser::callback " << std::endl;
}
};
template<class SqlParser>class SqlCommand
{
public:
SqlCommand(char * sql, SqlParser parser)
: m_parser(parser), m_sql(sql)
{
}
int executeQuery()
{
std::cout << m_sql << std::endl;
return sql_exec_cpp(m_sql);
}
private:
int sql_exec_cpp(const char * sql)
{
return sql_exec(sql, SqlParser::Callback);
}
private:
SqlParser m_parser;
char * m_sql;
}
;
int main(){
char * sql = "select * from sqlParser;
";
SqlCommand<SqlParser> sqlcmd(sql, SqlParser());
sqlcmd.executeQuery();
char * addrSql = "select * from address;
";
SqlCommand<AddressParser> addrSqlCmd(addrSql, AddressParser());
addrSqlCmd.executeQuery();
return 0;
}