2009-06-05 159 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();