可以传递类方法而不是函数,并提供不同的 this 指针吗?

huangapple go评论63阅读模式
英文:

Is it possible to pass class method instead of function and provide diffrent this pointer

问题

void f(int(*fp)(C*,int)){
    C c(20);
    std::cout << fp(&c, 5) << std::endl;
}
英文:
#include &lt;iostream&gt;

class C{
private:
    int a;
public:
    C(int a):a(a){};
    int m(int b){
            return a + b;
    }
};
void f(int(*fp)(C*,int)){
    C c(20);
    std::cout &lt;&lt; fp(&amp;c, 5) &lt;&lt; std::endl;
}

int main(int argc, char *argv[]) {
    C c(10);
    f(reinterpret_cast&lt;int(*)(C*,int)&gt;(c.m)); //has to be function pointer
    return 0;
}

This cast obviously doesn't work.

It can't be static method.

f needs to have this signature.

答案1

得分: 2

以下是翻译好的部分:

当你需要传递指针给一个方法时,可以像这样做:

```cpp
#include <iostream>

class C {
private:
    int a;
public:
    C(int a) : a(a) {}
    int add(int b) { return a + b; }
    int sub(int b) { return a - b; }
};

void f(int (C::*fp)(int)) {
    C c(20);
    std::cout << (c.*fp)(5) << std::endl;
}

int main() {
    f(&C::add);
    f(&C::sub);
}

上面的示例在函数 f 中仍然使用了硬编码的 C 实例。如果你想要在不同的 C 实例上调用方法,那么你应该传递一个对象的引用(或指针):

void f(C &c, int (C::*fp)(int)) {
    std::cout << (c.*fp)(5) << std::endl;
}

int main() {
    C foo(10), bar(20);
    f(foo, &C::add);
    f(foo, &C::sub);
    f(bar, &C::add);
    f(bar, &C::sub);
}

关于这段代码:

void f(int(*fp)(C*,int))

f 函数需要有这个签名。

嗯,如果你写适配器函数并使用 int (*fp)(C*, int) 这个签名,你还是可以做到这一点。你仍然需要从某个地方获取 C* 的值。它不能是隐式的。所以,回到你最初的例子,在函数 f 中硬编码了 C(20)

#include <iostream>

class C {
private:
    int a;
public:
    C(int a) : a(a) {}
    int add(int b) { return a + b; }
    int sub(int b) { return a - b; }
};

// 带有适当签名的适配器函数
int add(C* c, int b) { return c->add(b); }
int sub(C* c, int b) { return c->sub(b); }

void f(int (*fp)(C*, int)) {
    C c(20);
    std::cout << fp(&c, 5) << std::endl;
}

int main() {
    f(add);
    f(sub);
}
英文:

When you need to pass a pointer to a method, do it like this:

#include &lt;iostream&gt;

class C {
private:
    int a;
public:
    C(int a) : a(a) {}
    int add(int b) { return a + b; }
    int sub(int b) { return a - b; }
};

void f(int (C::*fp)(int)) {
    C c(20);
    std::cout &lt;&lt; (c.*fp)(5) &lt;&lt; std::endl;
}

int main() {
    f(&amp;C::add);
    f(&amp;C::sub);
}

The above example still uses a C instance hard-coded in the function f. If you want to call the method on different instances of C, then you should instead pass a reference (or pointer) to the object:

void f(C &amp;c, int (C::*fp)(int)) {
    std::cout &lt;&lt; (c.*fp)(5) &lt;&lt; std::endl;
}

int main() {
    C foo(10), bar(20);
    f(foo, &amp;C::add);
    f(foo, &amp;C::sub);
    f(bar, &amp;C::add);
    f(bar, &amp;C::sub);
}

Regarding this:

>
&gt; void f(int(*fp)(C*,int))
&gt;

> f needs to have this signature.

Well, you can sort-of do this if you write adapter functions with the signature int (*fp)(C*, int). You still need to get the C* value from somewhere. It cannot be implicit. So, going back to your original example that hard-codes C(20) in the function f:

#include &lt;iostream&gt;

class C {
private:
    int a;
public:
    C(int a) : a(a) {}
    int add(int b) { return a + b; }
    int sub(int b) { return a - b; }
};

// Adapters with the appropriate signature
int add(C* c, int b) { return c-&gt;add(b); }
int sub(C* c, int b) { return c-&gt;sub(b); }

void f(int (*fp)(C*, int)) {
    C c(20);
    std::cout &lt;&lt; fp(&amp;c, 5) &lt;&lt; std::endl;
}

int main() {
    f(add);
    f(sub);
}

答案2

得分: 0

Old school C-style function pointers aren't the C++ way to pass functions. If you're still working with C libraries, you're stuck, but if you control the code used, there are better ways.

This is a cut & paste from some of my code:

#include <functional>
...

typedef std::function<void(HTTPServerRequest &, HTTPServerResponse &)> Callback;

By using std::function you are enabling the use of non-static class methods or lambdas. I tend to prefer lambdas, because otherwise you also have to use std::bind, and I think that's ugly.

So if I can do this to define a Route constructor.

Route(const std::string &m, const std::string &p, const std::string &d, Route::Callback );

And I can pass that callback argument as:

[=](HTTPServerRequest &request, HTTPServerResponse &response) {
handleRequest(request, response);
}

(That's a lambda.) If I'm using this from some class, and handleRequest is a non-static method in that class, this works, and it's pretty clean.

You can also pass in C-style function pointers or use std::bind().

英文:

Old school C-style function pointers aren't the C++ way to pass functions. If you're still working with C libraries, you're stuck, but if you control the code used, there are better ways.

This is a cut & paste from some of my code:

#include &lt;functional&gt;
...

typedef std::function&lt;void(HTTPServerRequest &amp;, HTTPServerResponse &amp;)&gt; Callback;

By using std::function you are enabling the use of non-static class methods or lambdas. I tend to prefer lambdas, because otherwise you also have to use std::bind, and I think that's ugly.

So if I can do this to define a Route constructor.

Route(const std::string &amp;m, const std::string &amp;p, const std::string &amp;d, Route::Callback );

And I can pass that callback argument as:

[=](HTTPServerRequest &amp;request, HTTPServerResponse &amp;response) {
    handleRequest(request, response);
}

(That's a lambda.) If I'm using this from some class, and handleRequest is a non-static method in that class, this works, and it's pretty clean.

You can also pass in C-style function pointers or use std::bind().

huangapple
  • 本文由 发表于 2023年4月20日 03:49:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76058313.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定