Как передать указатель на функцию, которая указывает на конструктор? - PullRequest
33 голосов
/ 05 июня 2009

Я работаю над реализацией механизма отражения в C ++. Все объекты в моем коде являются подклассом Object (мой собственный универсальный тип), который содержит статические данные о членах типа Class.

class Class{
public:
   Class(const std::string &n, Object *(*c)());
protected:
   std::string name;     // Name for subclass
   Object *(*create)();  // Pointer to creation function for subclass
};

Для любого подкласса Object со статическим значением члена класса я хочу иметь возможность инициализировать 'create' указателем на конструктор этого подкласса.

Ответы [ 6 ]

58 голосов
/ 05 июня 2009

Вы не можете взять адрес конструктора (C ++ 98 Стандарт 12.1 / 12 Конструкторы - «12.1-12 Конструкторы -« Адрес конструктора не должен быть взят ».)

Лучше всего иметь заводскую функцию / метод, который создает Object и передавать адрес фабрики:

class Object;

class Class{
public:
   Class(const std::string &n, Object *(*c)()) : name(n), create(c) {};
protected:
   std::string name;     // Name for subclass
   Object *(*create)();  // Pointer to creation function for subclass
};

class Object {};

Object* ObjectFactory()
{
    return new Object;
}



int main(int argc, char**argv)
{
    Class foo( "myFoo", ObjectFactory);

    return 0;
}
3 голосов
/ 26 мая 2017

Я столкнулся с этой же проблемой. Моим решением была функция шаблона, которая вызывала конструктор.

template<class T> MyClass* create()
{
    return new T;
}

Использовать это как указатель на функцию просто:

MyClass* (*createMyClass)(void) = create<MyClass>;

И чтобы получить экземпляр MyClass:

MyClass* myClass = createMyClass();
2 голосов
/ 11 декабря 2016

Лямбда-стиль:

[](){return new YourClass();}
2 голосов
/ 05 июня 2009

Хм, странно. create - это переменная-член, т. Е. Доступная только в экземплярах классов, но, по-видимому, ее целью является создание экземпляра.

Вы не можете взять адрес конструктора, но вы можете создать свои собственные статические фабричные методы и взять адрес этого.

1 голос
/ 05 июня 2009

Вы не можете использовать обычные указатели на методы, вы должны использовать указатели на методы, которые имеют причудливый синтаксис:

void (MyClass::*method_ptr)(int x, int y);
method_ptr = &MyClass::MyMethod;

Это дает вам указатель на метод MyClass - MyMethod. Однако это не настоящий указатель в том смысле, что это не абсолютный адрес памяти, это в основном смещение (более сложное, чем из-за виртуального наследования, но это зависит от реализации) класса. Таким образом, чтобы использовать указатель на метод, вы должны предоставить ему класс, например:

MyClass myclass;
myclass.*method_ptr(x, y);

или

MyClass *myclass = new MyClass;
myclass->*method_ptr(x, y);

Конечно, в этот момент должно быть очевидно, что вы не можете использовать указатель метода для указания на конструктор объектов. Чтобы использовать указатель на метод, вам нужно иметь экземпляр класса, чтобы его конструктор уже был вызван! Так что в вашем случае, вероятно, лучший способ сделать это - предложение фабрики объектов Майкла.

0 голосов
/ 04 сентября 2015

Используя Qt, вы можете вызывать конструктор с механизмами отражения Qt (QMetaObject), если объявляете конструктор как Q_INVOKABLE (ничего больше, чем это).

class MyClass : public QObject {
   Q_OBJECT
public:
   Q_INVOKABLE MyClass(int foo);
   MyClass *cloningMySelf() {
     return metaObject()->newInstance(Q_ARG(int, 42));
   }
};

Я не уверен, что вы захотите встроить Qt только для этой функции ;-), но, возможно, вы хотели бы посмотреть, как это происходит.

http://doc.qt.io/qt-5/metaobjects.html#meta-object-system

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...