好吧,我经常看到使用以下类型的事件处理:
Connect(objectToUse, MyClass::MyMemberFunction);
用于某些类型的事件处理,其中objectToUse的类型为MyClass。我的问题是,这到底是如何工作的。您如何将其转换为可以执行objectToUse->MyMemberFunction()的内容
MyClass::MyMemberFunction是否给出了一个从类的开头开始的偏移量,然后可以用作函数指针?
发布于 2013-03-01 08:39:54
除了Mats的回答之外,我还将给您一个简短的示例,说明如何在这类事情中使用非静态成员函数。如果您不熟悉指向成员函数的指针,则可能需要先查看FAQ。
然后,考虑这个(相当简单)的例子:
class MyClass
{
public:
int Mult(int x)
{
return (x * x);
}
int Add(int x)
{
return (x + x);
}
};
int Invoke(MyClass *obj, int (MyClass::*f)(int), int x)
{ // invokes a member function of MyClass that accepts an int and returns an int
// on the object 'obj' and returns.
return obj->*f(x);
}
int main(int, char **)
{
MyClass x;
int nine = Invoke(&x, MyClass::Mult, 3);
int six = Invoke(&x, MyClass::Add, 3);
std::cout << "nine = " << nine << std::endl;
std::cout << "six = " << six << std::endl;
return 0;
}发布于 2013-03-01 08:35:40
通常,这使用一个static成员函数(它接受一个指针作为参数),在这种情况下,objectToUse作为参数传入,MyMemberFunction将使用objectToUse设置一个指向MyClass对象的指针,并使用该指针引用成员变量和成员函数。
在本例中,Connect将包含如下内容:
void Connect(void *objectToUse, void (*f)(void *obj))
{
...
f(objectToUse);
...
}f和objectToUse也很有可能被保存在某个地方供以后使用,而不是实际在Connnect内部使用,但在这种情况下调用看起来也是一样的-只是从其他一些函数调用,因为这个函数应该被调用。
也可以使用指向成员函数的指针,但这相当复杂,而且很难“正确”-无论是在语法方面还是在“何时和如何正确使用它”方面。请参阅更多here。
在这种情况下,Connect看起来有点像这样:
void Connect(MyClass *objectToUse, void (Myclass::*f)())
{
...
objectToUse->*f();
...
}使用模板的可能性很大,就好像"MyClass“在Connect类中是已知的一样,所以使用函数指针是没有意义的。虚拟函数将是一个更好的选择。
在适当的情况下,您也可以使用虚函数作为成员函数指针,但这需要编译器/环境“配合”。这里有一些关于这个主题的更多细节[我没有任何个人经验:指向虚拟成员函数的指针]。它怎麽工作?
Vlad还指出了函数器,它是包装函数的对象,允许具有特定行为的对象作为“函数对象”传入。通常,这涉及到一个预定义的成员函数或一个operatorXX,它们作为需要回调到代码的函数中处理的一部分来调用。
C++11允许"Lambda函数“,这是在代码中动态声明的函数,没有名称。这是我根本没有用过的东西,所以我不能对此做进一步的评论--我已经读到过它,但在我的(爱好)编程中并不需要使用它--尽管我也在C++上工作了5年,但我大部分的工作时间都是用C语言,而不是C++。
发布于 2013-03-01 08:40:03
我可能错了,但据我所知,
在C++中,具有相同签名的函数是相等的。
带有n个参数的C++成员函数实际上是带有n+1参数的普通函数。换句话说,void MyClass::Method( int i )实际上就是void (some type)function( MyClass *ptr, int i)。
因此,我认为Connect在幕后工作的方式是将成员方法签名转换为普通函数签名。它还需要一个指向实例的指针才能真正使连接工作,这就是它需要objectToUse的原因
换句话说,它本质上是使用指向函数的指针,并将它们转换为更通用的类型,直到可以使用提供的参数和附加参数调用它,该参数是指向对象实例的指针
如果方法是静态的,那么指向实例的指针就没有意义,它是直接的类型转换。我还没有弄清楚非静态方法所涉及的复杂性--看看boost::bind的内部结构可能是你想要理解的:)下面是它是如何工作于静态函数的。
#include <iostream>
#include <string>
void sayhi( std::string const& str )
{
std::cout<<"function says hi "<<str<<"\n";
}
struct A
{
static void sayhi( std::string const& str )
{
std::cout<<"A says hi "<<str<<"\n";
}
};
int main()
{
typedef void (*funptr)(std::string const&);
funptr hello = sayhi;
hello("you"); //function says...
hello = (&A::sayhi); //This is how Connect would work with a static method
hello("you"); //A says...
return 0;
}https://stackoverflow.com/questions/15148302
复制相似问题