web-dev-qa-db-fra.com

Comment passer un pointeur de fonction qui pointe vers constructeur?

Je travaille sur l'implémentation d'un mécanisme de réflexion en C++. Tous les objets de mon code sont une sous-classe de Object (mon propre type générique) contenant une donnée de membre statique de type 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
};

Pour toute sous-classe d'Object avec une donnée de membre de classe statique, je veux pouvoir initialiser 'create' avec un pointeur sur le constructeur de cette sous-classe.

30
Kareem

Vous ne pouvez pas prendre l'adresse d'un constructeur (Constructeurs C++ 98 Standard 12.1/12 - "Constructeurs 12.1-12 -" L'adresse d'un constructeur ne doit pas être prise. ")

Votre meilleur choix est d’avoir une fonction/méthode d’usine qui crée la Object et transmette l’adresse de l’usine:

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;
}
57
Michael Burr

Hmm, étrange. create est une variable membre, c'est-à-dire uniquement disponible dans les instances de classe, mais son objectif semble être de créer une instance.

Vous ne pouvez pas prendre l'adresse d'un constructeur, mais vous pouvez créer vos propres méthodes d'usine et en prendre l'adresse.

2
laalto

Vous ne pouvez pas utiliser les pointeurs de fonction habituels sur les méthodes, vous devez utiliser des pointeurs de méthode, qui ont une syntaxe bizarre:

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

Cela vous donne un pointeur de méthode sur la méthode de MyClass - MyMethod. Cependant, ce n'est pas un vrai pointeur dans la mesure où il ne s'agit pas d'une adresse de mémoire absolue, mais bien d'un décalage (plus compliqué que cela en raison de l'héritage virtuel, mais cette opération est spécifique à l'implémentation) dans une classe. Donc, pour utiliser le pointeur de méthode, vous devez lui fournir une classe, comme ceci:

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

ou

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

Bien entendu, il devrait être évident à ce stade que vous ne pouvez pas utiliser un pointeur de méthode pour pointer vers un constructeur d'objets. Pour utiliser un pointeur de méthode, vous devez avoir une instance de la classe afin que son constructeur ait déjà été appelé! Donc, dans votre cas, la suggestion de Michael Object Factory est probablement la meilleure façon de le faire.

1
Niki Yoshiuchi

Style Lambda:

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

J'ai rencontré le même problème. Ma solution était une fonction de modèle qui a appelé le constructeur. 

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

Utiliser ceci comme un pointeur de fonction est simple:

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

Et pour obtenir une instance de MyClass:

MyClass* myClass = createMyClass();
0
Andrew Wansink