Jor*_*tao 106 c++ arguments function-pointers parameter-passing pointer-to-member
问题如下:考虑这段代码:
#include <iostream>
class aClass
{
public:
void aTest(int a, int b)
{
printf("%d + %d = %d", a, b, a + b);
}
};
void function1(void (*function)(int, int))
{
function(1, 1);
}
void test(int a,int b)
{
printf("%d - %d = %d", a , b , a - b);
}
int main (int argc, const char* argv[])
{
aClass a();
function1(&test);
function1(&aClass::aTest); // <-- How should I point to a's aClass::test function?
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我如何使用a
's aClass::test
作为参数function1
?我坚持这样做.
我想访问该班级的成员.
Die*_*ühl 128
使用函数指针没有任何问题.但是,指向非静态成员函数的指针与普通函数指针不同:需要在对象上调用成员函数,该对象作为函数的隐式参数传递.因此,上面的成员函数的签名是
void (aClass::*)(int, int)
Run Code Online (Sandbox Code Playgroud)
而不是你尝试使用的类型
void (*)(int, int)
Run Code Online (Sandbox Code Playgroud)
一种方法可以包括制作成员函数,static
在这种情况下,它不需要调用任何对象,您可以将其与类型一起使用void (*)(int, int)
.
如果您需要访问类的任何非静态成员 和你需要坚持使用函数指针,例如,因为函数是C接口的一部分,你最好的选择是始终传递void*
给你的函数以函数指针和呼叫您的成员通过转发函数从中获取对象void*
然后调用成员函数.
在适当的C++接口中,您可能希望查看函数对函数对象使用模板化参数来使用任意类类型.如果不希望使用模板化接口,则应使用以下内容std::function<void(int, int)>
:您可以为这些创建适当可调用的函数对象,例如,使用std::bind()
.
使用类型或适当类型的模板参数的类型安全方法std::function<...>
优于使用void*
接口,因为它们消除了由于转换为错误类型而导致错误的可能性.
为了阐明如何使用函数指针来调用成员函数,这里有一个例子:
// the function using the function pointers:
void somefunction(void (*fptr)(void*, int, int), void* context) {
fptr(context, 17, 42);
}
void non_member(void*, int i0, int i1) {
std::cout << "I don't need any context! i0=" << i0 << " i1=" << i1 << "\n";
}
struct foo {
void member(int i0, int i1) {
std::cout << "member function: this=" << this << " i0=" << i0 << " i1=" << i1 << "\n";
}
};
void forwarder(void* context, int i0, int i1) {
static_cast<foo*>(context)->member(i0, i1);
}
int main() {
somefunction(&non_member, 0);
foo object;
somefunction(&forwarder, &object);
}
Run Code Online (Sandbox Code Playgroud)
Mat*_*ips 73
@Pete Becker的答案很好,但您也可以在不将class
实例作为function1
C++ 11中的显式参数传递的情况下执行此操作:
#include <functional>
using namespace std::placeholders;
void function1(std::function<void(int, int)> fun)
{
fun(1, 1);
}
int main (int argc, const char * argv[])
{
...
aClass a;
auto fp = std::bind(&aClass::test, a, _1, _2);
function1(fp);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Pet*_*ker 45
指向成员函数的指针与指向函数的指针不同.为了通过指针使用成员函数,您需要一个指向它的指针(显然)和一个要应用它的对象.所以适当的版本function1
将是
void function1(void (aClass::*function)(int, int), aClass& a) {
(a.*function)(1, 1);
}
Run Code Online (Sandbox Code Playgroud)
并称之为:
aClass a; // note: no parentheses; with parentheses it's a function declaration
function1(&aClass::test, a);
Run Code Online (Sandbox Code Playgroud)
我问了一个类似的问题(C++ openframeworks moving void from other classes),但我发现的答案更清晰,所以这里是对未来记录的解释:
\n\nit\xe2\x80\x99s 更容易使用 std::function ,如下所示:
\n\n void draw(int grid, std::function<void()> element)\n
Run Code Online (Sandbox Code Playgroud)\n\n然后调用为:
\n\n grid.draw(12, std::bind(&BarrettaClass::draw, a, std::placeholders::_1));\n
Run Code Online (Sandbox Code Playgroud)\n\n甚至更简单:
\n\n grid.draw(12, [&]{a.draw()});\n
Run Code Online (Sandbox Code Playgroud)\n\n在其中创建一个 lambda 调用通过引用捕获它的对象
\n需要注意的是,除非您可以更改采用该函数的代码的签名,否则没有(简单)的方法可以做到这一点。这将尝试用一种不具有与函数相同的闭包的语言来实现闭包(C++ 中闭包的签名不同)。
有两种实际方法可以实现此目的:
#include <stdio.h>
template<class C, typename ReturnType, typename... Args>
class ClosureSingleton {
typedef ReturnType (C::*FuncType)(Args...);
public:
static ClosureSingleton& getInstance() {
static ClosureSingleton instance;
return instance;
}
void setClosure(C* obj, FuncType f) {
this->obj = obj;
this->function = f;
}
static ReturnType funcPtr(Args... args) {
C* obj = getInstance().obj;
auto func = getInstance().function;
return (obj->*func)(args...);
}
private:
ClosureSingleton() {}
C* obj;
FuncType function;
public:
ClosureSingleton(ClosureSingleton const&) = delete;
void operator=(ClosureSingleton const&) = delete;
};
class aClass {
public:
void aTest1(int a, int b) { printf("%d + %d = %d\n", a, b, a + b); }
int aTest2(int a, int b) { return a + b; }
};
void function1(void (*function)(int, int)) {
function(1, 1);
}
int function2(int (*function)(int, int)) {
return function(1, 1);
}
int main() {
aClass tmp;
ClosureSingleton<aClass, void, int, int>::getInstance().setClosure(
&tmp, &aClass::aTest1);
function1(&ClosureSingleton<aClass, void, int, int>::funcPtr);
ClosureSingleton<aClass, int, int, int>::getInstance().setClosure(
&tmp, &aClass::aTest2);
printf(
"function2: %d\n",
function2(&ClosureSingleton<aClass, int, int, int>::funcPtr));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当然,这有一个明显的缺点,即每次调用之前都需要设置闭包,以及一些线程安全问题。不理想,但在特定情况下可能可行
我原来的答案并没有真正回答问题,但人们发现它很有用:
不知道为什么这个极其简单的解决方案被放弃了:
#include <stdio.h>
class aClass
{
public:
void aTest(int a, int b)
{
printf("%d + %d = %d\n", a, b, a + b);
}
};
template<class C>
void function1(void (C::*function)(int, int), C& c)
{
(c.*function)(1, 1);
}
void function1(void (*function)(int, int)) {
function(1, 1);
}
void test(int a,int b)
{
printf("%d - %d = %d\n", a , b , a - b);
}
int main (int argc, const char* argv[])
{
aClass a;
function1(&test);
function1<aClass>(&aClass::aTest, a);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
1 - 1 = 0
1 + 1 = 2
Run Code Online (Sandbox Code Playgroud)
从2011年开始,如果您可以更改function1
,请按照以下步骤进行操作:
#include <functional>
#include <cstdio>
using namespace std;
class aClass
{
public:
void aTest(int a, int b)
{
printf("%d + %d = %d", a, b, a + b);
}
};
template <typename Callable>
void function1(Callable f)
{
f(1, 1);
}
void test(int a,int b)
{
printf("%d - %d = %d", a , b , a - b);
}
int main()
{
aClass obj;
// Free function
function1(&test);
// Bound member function
using namespace std::placeholders;
function1(std::bind(&aClass::aTest, obj, _1, _2));
// Lambda
function1([&](int a, int b) {
obj.aTest(a, b);
});
}
Run Code Online (Sandbox Code Playgroud)
还要注意,我修复了损坏的对象定义(aClass a();
声明了一个函数)。