【问题标题】:Issue in function pointer函数指针问题
【发布时间】:2020-11-27 06:15:50
【问题描述】:

在.hpp 文件中

class trees
{
    public:
        virtual void func();
    private:
        void world(uint8_t alpha, uint8_t beta);
}

在 a.cpp 中

#include "a.hpp"
void trees::world(uint8_t alpha, uint8_t beta)
{
    
}
void trees::func()
{
    hello( hi, world ); //error
}

其中helloplant 在单独的文件中如下:

int hello(struct b* c, plant d);  
typedef void plant(uint8_t alpha, uint8_t beta); 

第 2nd 参数给出错误提示 (tress::*) is not compatible with parameter of type world

我知道我需要实例化 obj,但我不知道该怎么做。

【问题讨论】:

  • @churill "hello(hi,world) 在函数内部被调用。我已经编辑了问题。现在有意义吗?
  • hello 不是tree 的成员,因此它不知道其他tree 成员,例如tree::world。此外,(非静态)成员函数等于非成员函数。成员函数需要调用对象,而非成员函数不需要。这有很大的不同。
  • @Someprogrammerdude 我错了,我刚刚编辑了问题

标签: c++ function-pointers pointer-to-member


【解决方案1】:

函数指针和成员函数指针不是一回事。

这段代码会编译

class trees
{
    public:
       void world(uint8_t alpha, uint8_t beta);
};

typedef void (trees::*plant)(uint8_t alpha, uint8_t beta);

int hello(struct b* c, plant d);

void func()
{
    b* hi = ...;
    hello(hi, &trees::world);
}

但是你仍然需要一个trees 对象来调用你的方法函数指针所指向的方法。您发布的代码中没有任何内容表明它来自哪里。

假设p是一个指向trees对象的指针,那么使用指针d调用方法的语法是(p->*d)(1, 2);

【讨论】:

  • typedef void (trees::*plant)(uint8_t alpha, uint8_t beta); - 这对我来说是一条不可改变的线。它来自设备驱动程序。所以我将无法更改它
  • @galaxy2096 那么你不能将非静态成员函数传递给你的例程。函数指针和成员函数指针不兼容。静态成员函数就可以了。
  • 其实func是trees类中的公共方法,我只是编辑了问题
  • @galaxy2096 好的,但这不会改变基本问题。
  • @galaxy2096 典型的解决方案是将world 方法更改为static,然后从该静态方法调用非静态方法。这要求您在某处保存指向trees 对象的指针。最坏的情况是您为此创建了一个全局变量。
【解决方案2】:

指向成员的指针是一个非常不同的野兽,因为它必须绑定到一个特定实例,以便您可以访问该实例的成员,因为每个对象可能有不同的成员偏移量(对于属性)和不同的方法(用于虚拟方法)。静态方法 OTOH 与全局函数完全一样,只是位于不同的命名空间中,因此您不需要对象来调用它。因此,如果您不需要访问任何私有成员,则只需使用静态成员

static void world(uint8_t alpha, uint8_t beta);

如果您确实需要访问私有成员,那么有几种方法无需更改签名:

  • 声明world为友元函数

  • 使用std::bind

    trees tree; // the tree instance
    auto plant = std::bind(&trees::world, &tree, _1, _2);
    

    那么plant(alpha, beta) 将与(tree.*world)(alpha, beta); 相同

“指向成员函数”的类型与“指向函数”的类型不同吗?

是的。

考虑以下函数:

int f(char a, float b);

根据是普通函数还是某个类的非静态成员函数,这个函数的类型不同:

  • 如果是普通函数,它的类型是int (*)(char,float)
  • 如果是 Fred 类的非静态成员函数,则其类型为 int (Fred::*)(char,float)

注意:如果是Fred类的静态成员函数,其类型和普通函数一样:int (*)(char,float)

https://isocpp.org/wiki/faq/pointers-to-members#fnptr-vs-memfnptr-types

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-31
    • 2016-07-31
    • 2011-09-09
    • 2012-04-02
    • 2017-01-09
    • 2017-12-03
    • 1970-01-01
    相关资源
    最近更新 更多