C ++ - альтернатива вызову указателей на функции базового класса - PullRequest
0 голосов
/ 06 мая 2018

Я нашел много постов, где было довольно ясно сказано, что функция производного класса не может быть назначена указателю функции базового класса. Поэтому я хочу знать, как подойти и решить следующую ситуацию:

Предположим, у меня есть следующая база class

class base {
protected:
    typedef void (base::*base_fp)();
    typedef std::map<std::string, base_fp> array;

    array associativeArray;    
};

Основная цель этого класса - иметь свойство associative-array из functions.

Итак, я хотел, чтобы каждый производный ребенок мог добавлять свои методы в «ассоциативный массив»

this->associativeArray["Method"] = &child::method; // from the child class

Мое первоначальное намерение использовать это состояло в том, чтобы вызывать различные методы в зависимости от требования без использования условных операторов. Это было бы в блоке try-catch для обработки случая несуществующего индекса. Поскольку мой оригинальный подход не возможен, так каков будет правильный способ сделать это?

РЕДАКТИРОВАТЬ: Пример использования

Предположим, что ассоциативный массив является массивом "алгоритма" functions. Тогда для пользовательского «алгоритма» ввода я смогу вызвать соответствующий метод, определенный в дочернем классе

(this->*associativeArray.at("algorithm"))();

Ответы [ 2 ]

0 голосов
/ 06 мая 2018

Полагаю, вам нужно static_cast, потому что безопасно использовать две функции с одинаковыми сигнатурами, даже если они созданы из одной иерархии классов.

class base {

   protected:
     typedef void (base::*fn)() ;
     base(){
     fn_arr["foo"]=&base::foo;  
     }  
     void foo()  {
        cout << "i'm foo" << endl;
     }

   public:
     map<std::string, fn> fn_arr;
};

class derived : public base {

   protected:
      void bar() {
          cout <<"i'm bar" << endl;
      }

   public:
      derived() {
          fn_arr["bar"]=static_cast<fn>(&derived::bar);  
      }
};

см. Эту демонстрацию

0 голосов
/ 06 мая 2018

Самое близкое, что я могу получить к тому, что вы хотите, это использовать std::function (доступно с C ++ 11). Во-первых, мы изменим ваши typedef s, как для целей модернизации, так и для использования std::function:

class base {
protected:
    using base_fp = std::function<void ()>;
    using fn_array = std::map<std::string, base_fp>;
    fn_array fns;

public:
    void call_fn(std::string const &fn_name) {
        auto it = fns.find(fn_name);
        if(it != fns.end()) {
            it->second();
        }
        else {
            // error case
        }
    }
};

Поскольку fn_array хранит std::function с, оно будет работать со всем, что мы можем считать вызываемым. Это не может работать напрямую с функциями-членами (std::invoke может помочь, но я не использовал эту библиотечную функцию), но вы можете использовать тривиальные замыкания, чтобы получить аналогичное поведение.

class derived : public base {
public:
    derived() {
        fns["foo"] = [this]() { foo(); };
    }

private:
    void foo() {
        std::cout << __PRETTY_FUNCTION__ << '\n';
    }
};

Вы можете использовать это, используя следующий код:

int main() {
    derived d;
    d.call_fn("foo");
    return 0;
}
...