wake-up-neo.com

Wie übergebe ich einen Funktionszeiger, der auf den Konstruktor zeigt?

Ich arbeite an der Implementierung eines Reflexionsmechanismus in C++. Alle Objekte in meinem Code sind eine Unterklasse von Object (mein eigener generischer Typ), die ein statisches Elementdatum vom Typ Class enthält.

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

Für jede Unterklasse von Object mit einem statischen Klassenmitglieds-Datum möchte ich "create" mit einem Zeiger auf den Konstruktor dieser Unterklasse initialisieren können.

30
Kareem

Sie können die Adresse eines Konstruktors nicht übernehmen (C++ 98 Standard 12.1/12-Konstruktoren - "12.1-12-Konstruktoren -" Die Adresse eines Konstruktors darf nicht übernommen werden. ")

Am besten verwenden Sie eine Factory-Funktion/-Methode, mit der die Object erstellt und die Adresse der Factory übergeben wird:

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, merkwürdig. create ist eine Mitgliedsvariable, d. h. nur in Klasseninstanzen verfügbar, aber die Absicht, mit der sie erstellt wird, scheint in erster Linie eine Instanz zu sein.

Sie können die Adresse eines Konstruktors nicht übernehmen, aber Sie können eigene statische Factory-Methoden erstellen und die Adresse davon übernehmen.

2
laalto

Sie können keine regulären Funktionszeiger für Methoden verwenden. Sie müssen Methodenzeiger verwenden, die eine bizarre Syntax haben:

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

Dadurch erhalten Sie einen Methodenzeiger auf die Methode von MyClass - MyMethod. Dies ist jedoch kein echter Zeiger, da es sich nicht um eine absolute Speicheradresse handelt. Es handelt sich im Grunde genommen um einen Versatz (der aufgrund der virtuellen Vererbung komplizierter ist, aber das Zeug ist implementierungsspezifisch) in einer Klasse. Um den Methodenzeiger zu verwenden, müssen Sie ihn mit einer Klasse wie der folgenden versehen:

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

oder

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

Natürlich sollte an dieser Stelle klar sein, dass Sie keinen Methodenzeiger verwenden können, um auf einen Objektkonstruktor zu verweisen. Um einen Methodenzeiger verwenden zu können, muss eine Instanz der Klasse vorhanden sein, damit der Konstruktor bereits aufgerufen wurde! In Ihrem Fall ist der Vorschlag von Michael für die Objektfabrik wahrscheinlich der beste Weg, dies zu tun.

1
Niki Yoshiuchi

Lambda-Stil:

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

Ich bin auf dasselbe Problem gestoßen. Meine Lösung war eine Template-Funktion, die den Konstruktor aufgerufen hat.

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

Dies als Funktionszeiger zu verwenden ist einfach:

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

Und um eine Instanz von MyClass zu erhalten:

MyClass* myClass = createMyClass();
0
Andrew Wansink