2009-06-05 4 views
28

Я работаю над реализацией механизма отражения в 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 со статическим данности члена класса, я хочу, чтобы иметь возможность инициализировать «создать» с указателем на конструктору этого подкласса.

+0

Хотя это 6 лет после факта - вы должны дать много думал о том, действительно ли вы хотите реализовать свой собственный механизм размышления. Сначала рассмотрим возможность расчета для «отражения» времени компиляции с использованием шаблонов, type_traits и принципа SFINAE; затем попробуйте одну из существующих библиотек отражения C++; и только тогда я подумал бы о том, чтобы пойти на него сам. – einpoklum

ответ

52

Вы не можете взять адрес конструктора (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; 
} 
+5

Создание этого шаблона заставит его фактически вернуть «Класс»: template Object * ObjectFactory() {return new T; } .... Класс foo ("myFoo", & ObjectFactory ); –

2

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

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

+1

laalto, Когда я создаю объект класса, я передаю имя и функцию создания. Моя цель - иметь список классов, к которым я могу обратиться в любом месте моего проекта. Будет работать указатель на статическую функцию-член. – Kareem

+0

И добавьте еще одну косвенность - плохо для производительности. – Lothar

0

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

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); 

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

+6

Неправильно. & MyClass :: MyMethod дает вам адрес в памяти фактического исполняемого кода MyMethod. Методы имеют неявный первый аргумент, этот указатель. Вы не предоставляете метод с классом, вы поставляете его с объектом (экземпляр класса, например, этот указатель). Перейдите по ссылке thecall calling. –

+1

Я должен добавить, что есть больше магии, связанной с получением местоположения кода для вызова, если метод является виртуальным, но существование методов никоим образом не зависит от существования какого-либо экземпляра класса. –

+0

А, так вы правы. Концептуально это мало чем отличается от OP, так как указатель метода не будет работать, если не существует экземпляр класса. Я исправил свой пост, чтобы отразить это. –

0

Используя 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

1

Lambda стиль:

[](){return new YourClass();} 
+1

Пожалуйста, подумайте над тем, чтобы добавить больше объяснений/контекста, поскольку это делает ответ более полезным для будущих читателей. – EJoshuaS

+0

Определенно отметим, что это функция C++ 11 и более поздняя. – Kareem

0

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

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

Чтобы использовать это в качестве указателя функции прост:

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

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

MyClass* myClass = createMyClass();