通过函数指针调用 C++ 类方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1485983/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Calling C++ class methods via a function pointer
提问by Tony the Pony
How do I obtain a function pointer for a class member function, and later call that member function with a specific object? I'd like to write:
如何获取类成员函数的函数指针,然后使用特定对象调用该成员函数?我想写:
class Dog : Animal
{
Dog ();
void bark ();
}
…
Dog* pDog = new Dog ();
BarkFunction pBark = &Dog::bark;
(*pBark) (pDog);
…
Also, if possible, I'd like to invoke the constructor via a pointer as well:
另外,如果可能,我还想通过指针调用构造函数:
NewAnimalFunction pNew = &Dog::Dog;
Animal* pAnimal = (*pNew)();
Is this possible, and if so, what is the preferred way to do this?
这是可能的,如果是这样,这样做的首选方法是什么?
回答by Satbir
Read thisfor detail :
阅读这个详细:
// 1 define a function pointer and initialize to NULL
int (TMyClass::*pt2ConstMember)(float, char, char) const = NULL;
// C++
class TMyClass
{
public:
int DoIt(float a, char b, char c){ cout << "TMyClass::DoIt"<< endl; return a+b+c;};
int DoMore(float a, char b, char c) const
{ cout << "TMyClass::DoMore" << endl; return a-b+c; };
/* more of TMyClass */
};
pt2ConstMember = &TMyClass::DoIt; // note: <pt2Member> may also legally point to &DoMore
// Calling Function using Function Pointer
(*this.*pt2ConstMember)(12, 'a', 'b');
回答by gavinb
How do I obtain a function pointer for a class member function, and later call that member function with a specific object?
如何获取类成员函数的函数指针,然后使用特定对象调用该成员函数?
It's easiest to start with a typedef
. For a member function, you add the classname in the type declaration:
从typedef
. 对于成员函数,在类型声明中添加类名:
typedef void(Dog::*BarkFunction)(void);
Then to invoke the method, you use the ->*
operator:
然后要调用该方法,请使用->*
运算符:
(pDog->*pBark)();
Also, if possible, I'd like to invoke the constructor via a pointer as well. Is this possible, and if so, what is the preferred way to do this?
另外,如果可能的话,我也想通过指针调用构造函数。这是可能的,如果是这样,这样做的首选方法是什么?
I don't believe you can work with constructors like this - ctors and dtors are special. The normal way to achieve that sort of thing would be using a factory method, which is basically just a static function that calls the constructor for you. See the code below for an example.
我不相信你可以使用这样的构造函数 - ctors 和 dtors 是特殊的。实现这种事情的正常方法是使用工厂方法,它基本上只是一个为您调用构造函数的静态函数。有关示例,请参阅下面的代码。
I have modified your code to do basically what you describe. There's some caveats below.
我已经修改了您的代码以基本上完成您所描述的操作。下面有一些注意事项。
#include <iostream>
class Animal
{
public:
typedef Animal*(*NewAnimalFunction)(void);
virtual void makeNoise()
{
std::cout << "M00f!" << std::endl;
}
};
class Dog : public Animal
{
public:
typedef void(Dog::*BarkFunction)(void);
typedef Dog*(*NewDogFunction)(void);
Dog () {}
static Dog* newDog()
{
return new Dog;
}
virtual void makeNoise ()
{
std::cout << "Woof!" << std::endl;
}
};
int main(int argc, char* argv[])
{
// Call member function via method pointer
Dog* pDog = new Dog ();
Dog::BarkFunction pBark = &Dog::makeNoise;
(pDog->*pBark)();
// Construct instance via factory method
Dog::NewDogFunction pNew = &Dog::newDog;
Animal* pAnimal = (*pNew)();
pAnimal->makeNoise();
return 0;
}
Now although you can normally use a Dog*
in the place of an Animal*
thanks to the magic of polymorphism, the type of a function pointer does notfollow the lookup rules of class hierarchy. So an Animal method pointer is not compatible with a Dog method pointer, in other words you can't assign a Dog* (*)()
to a variable of type Animal* (*)()
.
现在,尽管由于多态的魔力,您通常可以使用 aDog*
代替 an Animal*
,但函数指针的类型并不遵循类层次结构的查找规则。因此 Animal 方法指针与 Dog 方法指针不兼容,换句话说,您不能将 a 分配给Dog* (*)()
类型为 的变量Animal* (*)()
。
The static newDog
method is a simple example of a factory, which simply creates and returns new instances. Being a static function, it has a regular typedef
(with no class qualifier).
静态newDog
方法是工厂的一个简单示例,它只是创建并返回新实例。作为一个静态函数,它有一个正则typedef
(没有类限定符)。
Having answered the above, I do wonder if there's not a better way of achieving what you need. There's a few specific scenarios where you would do this sort of thing, but you might find there's other patterns that work better for your problem. If you describe in more general terms what you are trying to achieve, the hive-mind may prove even more useful!
回答了上述问题后,我确实想知道是否没有更好的方法来实现您的需求。在一些特定场景中,您会执行此类操作,但您可能会发现其他模式更适合您的问题。如果你用更笼统的术语来描述你想要实现的目标,蜂巢思维可能会更有用!
Related to the above, you will no doubt find the Boost bindlibrary and other related modules very useful.
与上述相关,您无疑会发现Boost 绑定库和其他相关模块非常有用。
回答by Steve314
I don't think anyone has explained here that one issue is that you need "member pointers" rather than normal function pointers.
我认为没有人在这里解释过一个问题是您需要“成员指针”而不是普通的函数指针。
Member pointers to functions are not simply function pointers. In implementation terms, the compiler cannot use a simple function address because, in general, you don't know the address to call until you know which object to dereference for (think virtual functions). You also need to know the object in order to provide the this
implicit parameter, of course.
函数的成员指针不仅仅是函数指针。在实现方面,编译器不能使用简单的函数地址,因为一般来说,在知道要取消引用哪个对象之前,您不知道要调用的地址(想想虚函数)。当然,您还需要知道对象才能提供this
隐式参数。
Having said that you need them, now I'll say that you really need to avoid them. Seriously, member pointers are a pain. It is much more sane to look at object-oriented design patterns that achieve the same goal, or to use a boost::function
or whatever as mentioned above - assuming you get to make that choice, that is.
说了你需要它们,现在我要说你真的需要避免它们。说真的,成员指针是一种痛苦。着眼于实现相同目标的面向对象设计模式,或者使用 aboost::function
或上面提到的任何东西 - 假设您可以做出那个选择,那就更明智了。
If you are supplying that function pointer to existing code, so you really needa simple function pointer, you should write a function as a static member of the class. A static member function doesn't understand this
, so you'll need to pass the object in as an explicit parameter. There was once a not-that-unusual idiom along these lines for working with old C code that needs function pointers
如果您要提供指向现有代码的函数指针,那么您确实需要一个简单的函数指针,您应该编写一个函数作为类的静态成员。静态成员函数无法理解this
,因此您需要将该对象作为显式参数传入。在处理需要函数指针的旧 C 代码时,曾经有过一个非常不寻常的习惯用法
class myclass
{
public:
virtual void myrealmethod () = 0;
static void myfunction (myclass *p);
}
void myclass::myfunction (myclass *p)
{
p->myrealmethod ();
}
Since myfunction
is really just a normal function (scope issues aside), a function pointer can be found in the normal C way.
由于myfunction
它实际上只是一个普通函数(范围问题除外),因此可以以普通 C 方式找到函数指针。
EDIT- this kind of method is called a "class method" or a "static member function". The main difference from a non-member function is that, if you reference it from outside the class, you must specify the scope using the ::
scope resolution operator. For example, to get the function pointer, use &myclass::myfunction
and to call it use myclass::myfunction (arg);
.
编辑- 这种方法称为“类方法”或“静态成员函数”。与非成员函数的主要区别在于,如果从类外部引用它,则必须使用::
范围解析运算符指定范围。例如,要获取函数指针,请使用&myclass::myfunction
并调用它 use myclass::myfunction (arg);
。
This kind of thing is fairly common when using the old Win32 APIs, which were originally designed for C rather than C++. Of course in that case, the parameter is normally LPARAM or similar rather than a pointer, and some casting is needed.
在使用旧的 Win32 API 时,这种事情很常见,这些 API 最初是为 C 而不是 C++ 设计的。当然在那种情况下,参数通常是 LPARAM 或类似的而不是指针,并且需要进行一些转换。
回答by AraK
typedef void (Dog::*memfun)();
memfun doSomething = &Dog::bark;
....
(pDog->*doSomething)(); // if pDog is a pointer
// (pDog.*doSomething)(); // if pDog is a reference
回答by eyelash
I came here to learn how to create a function pointer (not a method pointer) from a method but none of the answers here provide a solution. Here is what I came up with:
我来这里是为了学习如何从方法创建函数指针(不是方法指针),但这里的答案都没有提供解决方案。这是我想出的:
template <class T> struct MethodHelper;
template <class C, class Ret, class... Args> struct MethodHelper<Ret (C::*)(Args...)> {
using T = Ret (C::*)(Args...);
template <T m> static Ret call(C* object, Args... args) {
return (object->*m)(args...);
}
};
#define METHOD_FP(m) MethodHelper<decltype(m)>::call<m>
So for your example you would now do:
因此,对于您的示例,您现在将执行以下操作:
Dog dog;
using BarkFunction = void (*)(Dog*);
BarkFunction bark = METHOD_FP(&Dog::bark);
(*bark)(&dog); // or simply bark(&dog)
Edit:
Using C++17, there is an even better solution:
编辑:
使用 C++17,有一个更好的解决方案:
template <auto m> struct MethodHelper;
template <class C, class Ret, class... Args, Ret (C::*m)(Args...)> struct MethodHelper<m> {
static Ret call(C* object, Args... args) {
return (object->*m)(args...);
}
};
which can be used directly without the macro:
无需宏即可直接使用:
Dog dog;
using BarkFunction = void (*)(Dog*);
BarkFunction bark = MethodHelper<&Dog::bark>::call;
(*bark)(&dog); // or simply bark(&dog)
For methods with modifiers like const
you might need some more specializations like:
对于像const
您这样的带有修饰符的方法,您可能需要更多的专业化,例如:
template <class C, class Ret, class... Args, Ret (C::*m)(Args...) const> struct MethodHelper<m> {
static Ret call(const C* object, Args... args) {
return (object->*m)(args...);
}
};
回答by Benjamin
A function pointer to a class member is a problem that is really suited to using boost::function. Small example:
指向类成员的函数指针是一个真正适合使用 boost::function 的问题。小例子:
#include <boost/function.hpp>
#include <iostream>
class Dog
{
public:
Dog (int i) : tmp(i) {}
void bark ()
{
std::cout << "woof: " << tmp << std::endl;
}
private:
int tmp;
};
int main()
{
Dog* pDog1 = new Dog (1);
Dog* pDog2 = new Dog (2);
//BarkFunction pBark = &Dog::bark;
boost::function<void (Dog*)> f1 = &Dog::bark;
f1(pDog1);
f1(pDog2);
}
回答by hrnt
Reason why you cannot use function pointers to call member functions is that ordinary function pointers are usually just the memory address of the function.
不能使用函数指针调用成员函数的原因是普通函数指针通常只是函数的内存地址。
To call a member function, you need to know two things:
要调用成员函数,您需要知道两件事:
- Which member function to call
- Which instance should be used (whose member function)
- 调用哪个成员函数
- 应该使用哪个实例(其成员函数)
Ordinary function pointers cannot store both. C++ member function pointers are used to store a), which is why you need to specify the instance explicitly when calling a member function pointer.
普通函数指针不能同时存储两者。C++成员函数指针用于存储a),这就是为什么调用成员函数指针时需要显式指定实例的原因。
回答by Corwin Joy
To create a new object you can either use placement new, as mentioned above, or have your class implement a clone() method that creates a copy of the object. You can then call this clone method using a member function pointer as explained above to create new instances of the object. The advantage of clone is that sometimes you may be working with a pointer to a base class where you don't know the type of the object. In this case a clone() method can be easier to use. Also, clone() will let you copy the state of the object if that is what you want.
要创建一个新对象,您可以使用上面提到的放置新对象,或者让您的类实现一个 clone() 方法来创建对象的副本。然后,您可以使用如上所述的成员函数指针调用此克隆方法,以创建对象的新实例。克隆的优点是有时您可能会使用指向基类的指针,而您不知道对象的类型。在这种情况下,使用 clone() 方法会更容易。此外,如果您想要,clone() 将允许您复制对象的状态。