无法将 'void (myClass::*)()' 转换为 'void (*)()'。

4

所以,我知道这个问题在很多地方都有。但是没有一个例子能帮助我解决我的问题。

我正在尝试创建一个方法指针(在类中),因此它将根据特定条件寻址类的多个方法之一。

我试图使用静态函数进行操作(猜测我误解了如何操作的说明...),但没有成功。

以下是头文件:

class myClass
{
public:
    myClass(int value);

    void methodA(const string &msg);
    void methodB(const string &msg);

    void (*send_msg)(const string &msg);
};

还有 C++:

myClass::myClass(int value){
    if(value > 0){
        send_msg = &methodA
    }
    else{
        send_msg = &methodB
    }
}

对于一些已经了解的错误:

错误:ISO C++禁止获取未限定或括号化的非静态成员函数的地址以形成指向成员函数的指针。请说‘&myClass :: methodA’[- fpermissive]

错误:无法将“void(myClass :: *)(const string&){aka void(myClass :: *)(const std :: basic_string&)}”转换为“void(*)(const string&){aka void(*)(const std :: basic_string&)}”在赋值中

任何帮助都将不胜感激。

编辑感谢Jose,它可以编译:

void (myClass::*send_msg)(const string &msg);

同时也请完成以下任务:

send_msg = &myClass::methodA;

但是现在,当我试图使用这段代码时,我无法调用函数指针:

this->myClass_instance.send_msg(line); //*****getting error*****

this是其他类的实例时, 出现以下错误:

错误:必须使用“。”或“->”调用指向成员函数的指针,例如“(... -> *((otherClass *)this) -> otherClass :: myClass_instance.myClass :: send_msg)(...)”


使用std::function和lambda函数会更容易、更易读和更短,不是吗? - David Haim
@DavidHaim 我很乐意看到一个例子。 - Eli
你打算如何使用 send_msg - Barry
根据您的编辑,methodAmethodB应该是静态成员函数。 - songyuanyao
也许这并非你想要的(也许在现实生活中,你的代码比这个复杂得多),但是我不禁认为这是一种解决简单问题的非常复杂的方式。例如,派生类与纯虚函数以及工厂方法组合,是否会给你提供一个更易于维护和使用的解决方案?仅供参考。 - Component 10
3个回答

2

void (*send_msg)(const string &msg); 是用于自由函数或静态成员函数的指针声明,而不是非静态成员函数。你可能需要使用:

void (myClass::*send_msg)(const string &msg);

LIVE1

或者你可以将函数定义为静态成员函数:

static void methodA(const string &msg);
static void methodB(const string &msg);

LIVE2

对于第一个编译错误,当获取非静态成员函数的地址时,应该限定其名称(仅适用于第一种解决方案):

myClass::myClass(int value){
    if(value > 0){
        send_msg = &myClass::methodA;
                    ~~~~~~~~~
    }
    else{
        send_msg = &myClass::methodB;
                    ~~~~~~~~~
    }
}

2

我的示例: http://ideone.com/Vx4x88

通过添加myClass::,将send_msg变成类方法的指针。

void (myClass::*send_msg)(const string &msg);

此外,你好像漏掉了myClass::以及在末尾加上一个分号;
    send_msg = &myClass::methodA;
else
    send_msg = &myClass::methodB;

编辑:
因为你在评论中要求如何从类外部调用它:
myClass c(1);
(c.*c.send_msg)("hi");

或者

myClass * p = new myClass(1);
(p->*p->send_msg)("hi");

@Jose 谢谢。看起来已经编译通过了,但是当我尝试从外部调用它时,出现了“error: base operand of ‘->’ has non-pointer type ‘myClass’”的错误提示。 - Eli
@Eli,你给它起了什么名字? - songyuanyao
@Eli,请看这个链接 http://ideone.com/Vx4x88 并从那里开始工作。它有一个能够实现你想做的事情的工作示例(我还添加了一个称为“method”的新函数,可以更轻松地从外部调用)。在 ideone 的示例中向下滚动并检查输出结果。 - Jts
使用(c.*c.send_msg)("Hi");这个东西简直难以置信! - Eli

2

你也可以使用std::function

#include <functional>

class myClass
{
public:
    myClass(int value){
     if(value > 0){
        send_msg = [this](const std::string& str){ methodA(str); };
     }
     else{
         send_msg = [this](const std::string& str){ methodB(str); };
     }
    }

    void methodA(const string &msg);
    void methodB(const string &msg);

    std::function<void(const string &msg)> send_msg;
};

要调用该函数,只需使用()

myClass obj(10);
obj.send_msg("hi there");

但我认为问题是关于成员函数指针的,了解如何操作成员函数指针非常重要,而不是采用最简单的方法即std::function。主要原因是它有许多开销,如内存分配、虚函数调用,甚至空的std::function对象本身通常也非常大(在MSVC2015中至少有40个字节)。 - Jts
我倾向于选择最小开销。虽然我还没检查过,但我希望Jose的解决方案会更好。对两个回答都点赞。 - Eli
我同意这不是百分之百等同于成员函数,我想展示一种替代方法。无论如何,虽然缺点确实应该认真对待,但优点是std::function更容易、更安全,因为它不能为null或悬空。当调用一个空的std::function时,会抛出异常,而调用已置空/悬空的成员函数将具有未定义行为。 - David Haim
std::function 确实更容易,我同意,但是你可以有一个成员函数指针的引用,这样它就不会悬空。例如:const decltype(&methodA)& send_msg; (并且你可以在成员初始化列表中分配它)。而且只有 4 字节的开销。 - Jts

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