Come passare un puntatore a una funzione che punta al costruttore?

Sto lavorando per implementare un meccanismo di riflessione in C ++. Tutti gli oggetti all’interno del mio codice sono una sottoclass di Object (il mio stesso tipo generico) che contengono un membro statico di tipo 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 }; 

Per qualsiasi sottoclass di Object con un membro membro di una class statica, desidero essere in grado di inizializzare ‘create’ con un puntatore al costruttore di tale sottoclass.

Non puoi prendere l’indirizzo di un costruttore (C ++ 98 Standard 12.1 / 12 Costruttori – “12.1-12 Costruttori -” L’indirizzo di un costruttore non deve essere preso. “)

La cosa migliore è avere una funzione / metodo di fabbrica che crea l’ Object e passa l’indirizzo della fabbrica:

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

Hmm, strano. create è una variabile membro, vale a dire disponibile solo nelle istanze di class, ma l’intento di esso sembra essere la creazione di un’istanza in primo luogo.

Non puoi prendere l’indirizzo di un costruttore, ma puoi creare i tuoi metodi di fabbrica statici e prenderne l’indirizzo.

Non è ansible utilizzare puntatori di funzioni regolari sui metodi, è necessario utilizzare i puntatori del metodo, che hanno una syntax bizzarra:

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

Questo ti dà un puntatore del metodo al metodo di MyClass – MyMethod. Tuttavia questo non è un vero puntatore in quanto non è un indirizzo di memoria assoluto, è fondamentalmente un offset (più complicato di quello dovuto all’eredità virtuale, ma quella roba è specifica dell’implementazione) in una class. Quindi, per usare il puntatore del metodo, devi fornirlo con una class, come questa:

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

o

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

Ovviamente a questo punto dovrebbe essere ovvio che non è ansible utilizzare un puntatore del metodo per puntare a un costruttore di oggetti. Per usare un puntatore al metodo è necessario avere un’istanza della class, quindi è già stato chiamato il costruttore! Quindi nel tuo caso il suggerimento di Michael’s Object Factory è probabilmente il modo migliore per farlo.

Usando Qt, puoi chiamare un costruttore con meccanismi di riflessione Qt (QMetaObject) se dichiari il costruttore come Q_INVOKABLE (niente di più da fare).

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

Non sono sicuro che vorrà incorporare Qt solo per quella caratteristica 😉 ma forse ti piacerebbe dare un’occhiata al modo in cui lo fa.

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

Stile Lambda:

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

Ho incontrato questo stesso problema. La mia soluzione era una funzione template che chiamava il costruttore.

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

Utilizzare questo come puntatore a funzione è semplice:

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

E per ottenere un’istanza di MyClass:

 MyClass* myClass = createMyClass();