2009-06-05 184 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 
}; 

對於對象與類的靜態成員數據任何子類,我希望能夠初始化「創造」的指針該子類的構造函數。

+0

雖然這是事實,經過6年的 - 你應該給很多人想到你是否真的想實現自己的反射機制。首先考慮使用模板,type_traits和SFINAE原則來解決編譯時「反射」問題;然後嘗試一個現有的C++反射庫;只有到那時我纔會考慮親自去做。 – einpoklum 2015-12-15 21:41:19

回答

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; } .... Class foo(「myFoo」,&ObjectFactory ); – 2009-06-05 14:40:48

2

嗯,奇數create是一個成員變量即,僅在類實例可用,但它的目的似乎是創建

您無法獲取構造函數的地址,但可以創建自己的靜態工廠方法並獲取該地址。

+1

laalto, 當我構造Class對象時,我傳入一個名稱和一個創建函數。我的目標是在我的項目中任何地方都可以參考的類別列表。 指向靜態成員函數的指針將起作用。 – Kareem 2009-06-05 07:02:45

+0

並添加另一個間接 - 對性能不利。 – Lothar 2017-08-25 11:48:39

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實際可執行代碼的內存地址。方法有一個隱含的第一個參數,這個指針。你不提供一個類的方法,你提供一個對象(一個類的實例,例如這個指針)。去看看這個呼叫約定。 – 2009-06-05 19:35:03

+1

我必須補充說,如果方法是虛擬的,那麼在調用代碼的位置時會涉及更多的魔法,但方法的存在絕不取決於類的任何實例的存在。 – 2009-06-05 19:45:30

+0

啊,你說得對。從概念上說,它對OP沒有什麼不同,無論哪種方式,除非存在類的實例,否則方法指針將不起作用。 我修復了我的文章以反映這一點。 – 2009-06-05 20:19:17

0

使用Qt,如果你將構造函數聲明爲Q_INVOKABLE(除此之外沒什麼),你可以用Qt反射機制(QMetaObject)調用一個構造函數。

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 2016-12-11 06:11:34

+0

當然,提到這是一個C++ 11及更高版本的功能。 – Kareem 2016-12-14 21:15:17

0

我遇到了同樣的問題。我的解決方案是一個叫做構造函數的模板函數。

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

要使用此作爲一個函數指針很簡單:

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

而獲得MyClass的實例:

MyClass* myClass = createMyClass();