【问题标题】:Create method that accepts method from any child class创建接受来自任何子类的方法的方法
【发布时间】:2022-06-23 00:55:39
【问题描述】:

对于含糊的问题标题,我深表歉意,但我对 C++ 不够熟悉,无法更好地表述它。

我正在尝试创建一个将任何子类上的方法作为参数之一的方法,但我遇到了一个编译器错误,我不知道如何修复。我还想给类型起别名,这样它就不会那么冗长了。我对其他方法持开放态度,但我正在使用的代码或多或少是这样设置的。

代码:

#include <map>
#include <string>

using std::map;
using std::string;

struct ParentClass;
struct DataClass;

using my_handler_type = uint16_t (ParentClass::*)(DataClass&, DataClass&);

struct ParentClass {

    void add_handler(string name, my_handler_type handler) {
        handlers.emplace(name, handler);
    }

private:

    map<string, my_handler_type> handlers;

};

struct ChildClass : ParentClass {
    
private:

    uint16_t some_handling_function(DataClass &, DataClass & );

    void setup_handler() {
        add_handler( "handler_one", &ChildClass::some_handling_function );
    }

};

错误:

example.cpp: In member function ‘void ChildClass::setup_handler()’:
example.cpp:31:37: error: cannot convert ‘uint16_t (ChildClass::*)(DataClass&, DataClass&)’ {aka ‘short unsigned int (ChildClass::*)(DataClass&, DataClass&)’} to ‘my_handler_type’ {aka ‘short unsigned int (ParentClass::*)(DataClass&, DataClass&)’}
   31 |         add_handler( "handler_one", &ChildClass::some_handling_function );
      |                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                     |
      |                                     uint16_t (ChildClass::*)(DataClass&, DataClass&) {aka short unsigned int (ChildClass::*)(DataClass&, DataClass&) example.cpp:14:51: note:   initializing argument 2 of ‘void ParentClass::add_handler(std::string, my_handler_type)’
   14 |     void add_handler(string name, my_handler_type handler) {
      |                                   ~~~~~~~~~~~~~~~~^~~~~~~

【问题讨论】:

  • 最好解释一下为什么需要这个,听起来你有 xy 问题。
  • &amp;ChildClass::some_handling_functionshort unsigned int (ChildClass::*)(DataClass&amp;, DataClass&amp;),不能隐式转换为short unsigned int (ParentClass::*)(DataClass&amp;, DataClass&amp;)

标签: c++ c++20


【解决方案1】:

您可以将子类成员函数指针转换为基类成员函数指针的类型。

static_cast<my_handler_type>(&ChildClass::some_handling_function));

所以:

#include <iostream>
#include <map>
#include <string>

using std::map;
using std::string;

struct ParentClass;
struct DataClass {};

using my_handler_type = uint16_t (ParentClass::*)(DataClass &, DataClass &);

struct ParentClass {
    void add_handler(string name, my_handler_type handler) {
        handlers.emplace(name, handler);
    }

    void handle(const std::string &ev) {
        if (auto it = handlers.find(ev); it != handlers.end()) {
            DataClass d;
            (this->*it->second)(d, d);
        }
    }

private:
    map<string, my_handler_type> handlers;
};

struct ChildClass : ParentClass {
    uint16_t some_handling_function(DataClass &, DataClass &) {
        std::cout << "handling the stuff\n";
        return 0;
    }

public:
    void setup_handler() {
        // cast the member function pointer here:
        add_handler("handler_one", static_cast<my_handler_type>(
                                       &ChildClass::some_handling_function));
    }
};

int main() {
    ChildClass c;
    c.setup_handler();
    c.handle("handler_one");
}

Demo

【讨论】:

  • @AnoopRana 谢谢!是的,这很安全。我从不使用它。我想它会在一段时间后变得凌乱:)
  • 我同意。我曾经使用它here 来解决发布在 SO 上的问题,你会看到它变得非常难以阅读。
【解决方案2】:

问题是指向派生类成员函数的指针不能隐式转换为指向基类成员函数的指针。换句话说,short unsigned int (ChildClass::*)(DataClass&amp;, DataClass&amp;)不能隐式转换short unsigned int (ParentClass::*)(DataClass&amp;, DataClass&amp;)

但是您可以使用static_cast 将指向派生类成员函数的指针显式强制转换为指向基类成员函数的指针,就像在Ted's answer 中所做的那样。

【讨论】:

    【解决方案3】:

    好吧,我在这个问题上支持 πάντα ῥεῖ,但错误信息很简单。这个:

    using my_handler_type = uint16_t (ParentClass::*)(DataClass&, DataClass&);
    //                                ^^^^^^^^^^^
    

    与此不符:

    add_handler( "handler_one", &ChildClass::some_handling_function );
    //                           ^^^^^^^^^^ 
    
    

    你最好传入一个静态方法和一个'this'指针,该方法在此处作为参数,这将绕过这个问题(适合更改my_handler_type的定义)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-14
      • 1970-01-01
      • 2021-09-29
      相关资源
      最近更新 更多