如何从类方法返回成员函数指针?

How to return a member function pointer from a class method?

提问人:Johnson Jose 提问时间:6/25/2023 最后编辑:JeJoJohnson Jose 更新时间:6/25/2023 访问量:99

问:

我正在尝试使用类似策略模式的东西,其中有两个不同的解析器Type1ParserType2Parser使用接口IParser。 还有另一个类 ParsingText,我们有 2 个方法

  1. setParser:将设置解析器类型。
  2. getMethod 在解析器中返回一个方法。例如。格式化或解析
#include <iostream>
#include<vector>
#include<string>
using namespace std;

class IParser 
{
public:
    virtual ~IParser() = default;
    virtual string format() = 0;
    virtual string parse() = 0;
};

class Type1Parser :public IParser 
{
public:
    string format() override 
    {
        cout << " Formatting 1";
        return string();
    }
    string parse() override
    {
        cout << " Parsering 1";
        return string();
    }
};

class Type2Parser :public IParser 
{
public:
    string format() override 
    {
        cout << " Formatting 2";
        return string();
    }
    string parse() override 
    {
        cout << " Parsering 2";
        return string();
    }
};

typedef string(IParser::* parseFunc)();
class ParsingText
{
    IParser* parser;

public:
    void setParser(int p) 
    {
        if (p == 1) parser = new Type1Parser();
        if (p == 2) parser = new Type2Parser();
    }

    parseFunc getMethod(char o) 
    {
        if (o == 'f') return parser->format;
        else return parser->parse;
    }
};

int main() 
{
    ParsingText* pt = new ParsingText();

    pt->setParser(1);
    parseFunc myMethod = pt->getMethod('f');
    *myMethod();
    return 0;
}

我正在使用函数指针返回此类方法。但我做不到。 我不确定我在这里做错了什么?

C++ function-pointers 指向成员的指针 member-functions

评论

2赞 John Bayko 6/25/2023
您的计算机在运行时着火的问题吗?如果是这样,它可能不是此处发布的代码。另一方面,如果你准确地解释了“无法这样做”的含义(编译器错误、运行时崩溃、错误的输出等),那么有人可能会帮助你。
0赞 Johnson Jose 6/25/2023
编译器抛出一条消息,指出指向绑定函数的指针只能用于调用该函数
1赞 Igor Tandetnik 6/25/2023
在 中,make it - 这将使您通过错误消息。但是,为了通过指向成员函数的指针进行调用,您需要一个对象(实例或派生类)来调用它。的实例仅指向方法,但不指向要调用它的对象。如果你想将两者捆绑在一起,你需要返回例如,然后可以做getMethodreturn &IParser::format;IParserparseFuncstd::function<std::string()>getMethodreturn [=]() { return parser->format(); };
0赞 John Zwinck 6/25/2023
为什么要返回一个函数,而不仅仅是调用该函数?

答:

2赞 JeJo 6/25/2023 #1

我正在使用函数指针返回此类方法。但我做不到。我不确定我在这里做错了什么?

在 你正在尝试调用相应的成员函数,而不是返回它。正确的语法如下:getMethod

parseFunc getMethod(char o)
{
    if (o == 'f') return &IParser::format;  // ---> like this
    else          return &IParser::parse;   // ---> like this
}

这将解决编译器错误。但是,您现在有下一期。为了调用指向成员函数的指针,您还需要一个相应的对象实例,该实例仅在类中私有可用。例如,一种解决方案是提供一个 getter,并用它调用指向 member 的指针。ParsingTextparser

class ParsingText 
{
    // Use smart pointer rather than raw pointer(ex. std::unique_ptr)
    IParser* parser{ nullptr };
public:

    //  MEMORY LEAKS in setParser() !!!

    parseFunc getMethod(char o)
    {
        if (o == 'f') return &IParser::format;
        else          return &IParser::parse;
    }
    // Provided a getter for IParser
    IParser* getParser() { return parser; }
};

int main() 
{
    // Use smart pointer rather than raw pointer(ex. std::unique_ptr)
    auto pt{std::make_unique<ParsingText>()};

    pt->setParser(1);

    parseFunc myMethod = pt->getMethod('f');
    
    if (auto parser = pt->getParser())
    {
        (parser->*myMethod)(); // invoke with the Parser instance
        // or since C++17, from  <functional> header
        // std::invoke(myMethod, parser);
    }
    return 0;
}

观看 godbolt.org 中的现场演示


话虽如此,这可能不是您想要处理这种情况的方式。调用方端可能会更简洁,如果您返回了具有正确实例的被调用成员函数的包装版本。std::函数在这里派上用场。IParser

class ParsingText 
{
    // Use smart pointer rather than raw pointer(ex. std::unique_ptr)
    IParser* parser{ nullptr };
public:
    //  MEMORY LEAKS in setParser()!!!

    std::function<std::string()> invokeMethod(char o)
    {
        if (o == 'f' && parser) return [this] {return parser->format(); };
        else if (parser)        return [this] {return parser->parse(); };
        else return {}; // or some error handling
    }
};

int main() 
{
    // Use smart pointer rather than raw pointer(ex. std::unique_ptr)
    auto pt{std::make_unique<ParsingText>()};
    pt->setParser(1);

    auto callable = pt->invokeMethod('f'); // invoke like this
    callable();
}

观看 godbolt.org 中的现场演示