Я не знал точно, как озаглавить этот вопрос. У меня есть базовый класс и два наследующих класса:
class Base {};
class Action : public Base {};
class Title : public Base {};
Теперь скажем, у меня есть две функции, которые возвращают либо Action *
или же Title *
:
Action *getAction() { return new Action; }
Title *getTitle() { return new Title; }
Есть ли способ поместить эти две функции в карту? Вот так:
int main()
{
std::map<std::string, Base *(*)()> myMap;
myMap["action"] = getAction;
myMap["title"] = getTitle;
return 0;
}
Прямо сейчас я получаю ошибку:
invalid conversion from `Action* (*)()' to `Base* (*)()'
Я мог бы изменить сигнатуру функций, чтобы они всегда возвращали базовый класс, и тогда это сработало бы, но мне интересно, есть ли другой способ обойти это.
Если вы используете:
Base *getAction() { return static_cast<Base *>(new Action); }
Base *getTitle() { return static_cast<Base *>(new Title); }
тогда вы не получите эту ошибку.
std::function
является оберткой для указателя на полиморфную функцию, предоставляемой STL
Конечно, используя шаблоны, вы можете написать свою собственную функцию-обертку, которая хранит цель, передает аргументы вперед и выполняет преобразование. Это уже было сделано, и вы должны серьезно подумать, прежде чем вы решите бросить свой собственный. Если вы не любите изобретать колеса или предъявляете особые требования.
В качестве доказательства концепции у меня есть этот код:
#include <iostream>
#include <map>
#include <functional>
struct A
{
virtual void f() = 0;
};
struct B : public A
{
void f() { std::cout << "B::f\n"; }
};
struct C : public A
{
void f() { std::cout << "C::f\n"; }
};
B* getB() { return new B; }
C* getC() { return new C; }
int main()
{
std::map<std::string, std::function<A*()>> m;
m["b"] = getB;
m["c"] = getC;
m["b"]()->f();
m["c"]()->f();
}
Утечка памяти, но это работает.