43 Stimmen

Wie kann man einen Funktionszeiger übergeben, der auf einen 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 Mitgliedsdatenelement vom Typ Class enthalten.

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 Class-Member-Datum möchte ich in der Lage sein, 'create' mit einem Zeiger auf den Konstruktor dieser Unterklasse zu initialisieren.

0 Stimmen

Auch wenn dies erst 6 Jahre später geschieht - Sie sollten sich gut überlegen, ob Sie wirklich Ihre eigene Reflexionsmechanik einführen wollen. Überlegen Sie zunächst, ob Sie sich mit der Kompilierzeit-"Reflexion" unter Verwendung von Templates, type_traits und dem SFINAE-Prinzip zufrieden geben wollen; dann probieren Sie eine der vorhandenen C++-Reflection-Bibliotheken aus; und erst dann würde ich in Erwägung ziehen, es selbst zu versuchen.

1voto

Niki Yoshiuchi Punkte 15805

Sie können keine regulären Funktionszeiger auf Methoden verwenden, Sie müssen Methodenzeiger verwenden, die eine seltsame 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, sondern um einen Offset (der aufgrund der virtuellen Vererbung komplizierter ist, aber das ist implementierungsspezifisch) in einer Klasse. Um den Methodenzeiger zu verwenden, müssen Sie ihn also mit einer Klasse übermitteln, etwa so:

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

または

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

Natürlich sollte an dieser Stelle klar sein, dass man einen Methodenzeiger nicht verwenden kann, um auf einen Objektkonstruktor zu zeigen. Um einen Methodenzeiger zu verwenden, müssen Sie eine Instanz der Klasse haben, so dass ihr Konstruktor bereits aufgerufen wurde! In Ihrem Fall ist Michaels Vorschlag der Object Factory also wahrscheinlich die beste Lösung.

9 Stimmen

Das ist nicht korrekt. &MyClass::MyMethod gibt Ihnen die Adresse im Speicher des tatsächlich ausführbaren Codes von MyMethod. Methoden haben ein implizites erstes Argument, den this-Zeiger. Sie übergeben einer Methode keine Klasse, sondern ein Objekt (eine Instanz einer Klasse, z. B. einen this-Zeiger). Schlagen Sie die thiscall-Aufrufkonvention nach.

2 Stimmen

Ich muss noch hinzufügen, dass es mehr Magie gibt, um den Ort des aufzurufenden Codes zu finden, wenn die Methode virtuell ist, aber die Existenz der Methoden hängt in keiner Weise von der Existenz einer Instanz der Klasse ab.

0 Stimmen

Ah, Sie haben also Recht. Konzeptionell macht es wenig Unterschied zum OP, so oder so eine Methode Zeiger wird nicht funktionieren, wenn eine Instanz der Klasse existiert. Ich habe meinen Beitrag korrigiert, um dies zu berücksichtigen.

0voto

Jim Punkte 609

Mit Qt können Sie einen Konstruktor mit Qt-Reflection-Mechanismen (QMetaObject) aufrufen, wenn Sie den Konstruktor als Q_INVOKABLE deklarieren (mehr ist nicht zu tun).

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

Ich bin mir nicht sicher, ob Sie Qt nur wegen dieser Funktion einbinden wollen ;-), aber vielleicht möchten Sie einen Blick darauf werfen, wie es das tut.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X