C++函数指针作为参数和类?

6

嗯,我正在阅读一些指南,但是我无法弄清楚如何在C++中正确使用函数指针?

我有一个类,我希望在它完成当前操作后调用一个函数,像这样:

class WindowImages
{
    public:
        void Update()
        {
            for(unsigned int i = 0; i < _images.size(); i++)
            {
                //Do something
                _images[i]->MyFunctionPointer();
            }
        }
        void Add(Image* image, void (*func)(void))
        {
            image->function = func; //this is wrong
            _images.push_back(image);
        }         

    private:
        vector<Image*> _images;
}

class Image
{
    public:
        void ImageClicked();

        void *function(void);
};

void main()
{
    Image* image = new Image();

    WindowImages images;
    images.Add(image, image->ImageClicked);
}

我想把图像添加到向量中,然后传递一个函数作为参数,当图像类完成对每个图像的操作时,将调用该函数。 这些函数针对不同的图像,但它们都是以void function()格式编写的。
我尝试了很多方法,但一直没有结果,你能告诉我如何实现吗? 另外,如果你有一份更适合初学者的函数指针教程或指南(甚至是C++ 11 Lambda),那将非常有帮助!

4
你可以使用std::function而不是函数指针。 - Baum mit Augen
3
我认为 void *function(void); 声明了一个名为'function'的函数,其接受void类型参数并返回void指针。它不是一个函数指针。 - YoungJohn
4
你想声明一个函数指针 void (*function)(void);,但 成员函数指针 是不同的概念。 - jrok
3
为什么你要在这里使用成员函数指针,当你已经拥有对象并可以直接调用所需的函数呢? - Zac Howland
2
@Danicco 这正是为什么虚函数会更好的原因。它将为您提供一个更易于理解和实现的API,并使您(作为API设计者)的生活更加轻松。 - Zac Howland
显示剩余20条评论
3个回答

3

您的回调函数并不是使用普通的函数指针。您正在使用非静态成员函数指针,因此常规函数指针语法和调用机制将无法工作。在指针声明语法和调用非静态成员所使用的机制上存在显着差异。

要声明一个指向 Image 类的成员函数的指针,该成员函数不带参数且返回 void,语法应为:

void (Image::*function)(). 

调用成员函数可使用两个特殊运算符之一:->*(当使用对象指针时)或 .*(当使用对象引用时)。例如:

// declare a pointer to Image member function
void (Image::*function)();

// assign address of member function
function = &Image::ImageClicked;

// uses ->* for access
Image *pObj = new Image();
(pObj->*function)();

// uses .* for access
Image image;
(image.*function)();

希望这有所帮助。

1
基本上很接近,只有最后一部分应该是 (_images[i]->*function)()。除此之外看起来不错。希望那个电话打得不错。并且注意,这也适用于虚函数。在此处查看实际效果 - WhozCraig
我下次使用笔记本电脑时会添加适当的代码块。我正在搬家,可能需要几个小时。 - Manpat
@WhozCraig 好的,没问题。谢谢你。 - Manpat
@WhozCraig,Manpat:这个加上模板就可以了!还要感谢你们解释为什么之前不起作用(调用非静态函数,尽管你已经将其编辑掉),这让我更好地理解了这些函数指针! - Danicco
@Danicco 很高兴它起作用了。之前删除任何带来失败清晰度的内容并非有意,对此我很抱歉。但是非常高兴你明白为什么非静态成员需要 this 和运算符才能将其分派到成员函数中。话虽如此,我强烈建议听取这个问题中许多人的建议,考虑使用虚函数分派。它更加灵活。通常情况下,如果没有非常具体的原因,不要轻易使用成员函数指针,所以请考虑这一点。 - WhozCraig
显示剩余2条评论

0

首先,我认为您的意图最好通过C++多态性来实现,尽管这是通过底层的函数指针来完成的。C++函数指针教程。 以下代码可以实现您想要做的事情。

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
void f1() {
    cout << "f1()" << endl;
}
void f2() {
    cout << "f2()" << endl;
}
void f3() {
    cout << "f3()" << endl;
}    
class A {
public:
    void (*fp)();
};

class B {
public:
    void add(A* a, void (*fp)()) {
        a->fp = fp;
        vec_a.push_back(a);
    }
    ~B() {
        for (int i = 0; i < vec_a.size(); ++i) {
            vec_a[i]->fp();
        }
    }
private:
    vector<A*> vec_a;
};

int main() {
    B *b = new B();
    A* a[3];
    a[0] = new A();
    a[1] = new A();
    a[2] = new A();
    b->add(a[0], f1);
    b->add(a[1], f2);
    b->add(a[2], f3);
    delete b;
}

输出结果为

f1()
f2()
f3()

-2
首先,我建议不要在C++中使用函数指针。通常情况下,可以使用虚拟类来实现相同的功能。
在使用函数指针时,我发现typedef非常有用,可以使事情更加有条理。以下是一个有点牵强附会的例子,大致实现了您想要做的事情...
#include <stdio.h>
#include <vector>

typedef void (*fptr_type) (int);

void printSquare (int i) {
   printf ("%d\n", i * i);
   return;
}

void printDouble (int i) {
   printf ("%d\n", 2 * i);
   return;
}

class IntFPtrClass {
   public:
      int intVal;
      fptr_type fptr;

      IntFPtrClass (int i, fptr_type f) : intVal(i), fptr(f) { }

   // Just to show that static methods can be used as function pointers.
   static void printPlusOne(int i) {
      printf ("%d\n", i + 1);
      return;
   }
};

int main (void)
{
   std::vector<IntFPtrClass> my_vector;

   my_vector.push_back (IntFPtrClass(3, printSquare));
   my_vector.push_back (IntFPtrClass(5, printDouble));
   my_vector.push_back (IntFPtrClass(7, IntFPtrClass::printPlusOne));

   for (int i = 0; i < my_vector.size(); ++i)
   {
      my_vector[i].fptr(my_vector[i].intVal);
   }

   return 0;
}

我建议不要在C++中使用函数指针。总的来说,这个观点我完全不能赞同!这只是过于狭隘地看待了所有方面... - πάντα ῥεῖ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接