如何做一个运行时子类化系统
How to do a runtime subclassing system
我正在做一个子类化系统,可以在运行时定义。我有一个子类,它转发表(std::map
)的方法,如果表中没有方法,则使用超类方法。
示例(函数参数和返回类型不是问题,我只是简化了它):
class Superclass {
public:
virtual void doSomething();
};
class Superclass_subclass : public Superclass {
public:
std::map< std::string,std::function<void (Superclass_subclass*)> > table;
int doSomething(int a, int b) {
if( table.count("doSomething") == 0 ) return Superclass::doSomething(a,b);
return table.at("doSomething")(this,a,b);
}
};
现在我正在研究宏来简化创建_subclass
类的过程。现在我得到了以下宏:
#define runtime_subclass_begin(Superclass) //...
#define runtime_subclass_method(Superclass,rtype,method,args_def,args_call) //...
#define runtime_subclass_end
#define GROUP(...) __VA_ARGS__
runtime_subclass_begin(Superclass)
runtime_subclass_method(Superclass,int,doSomething,GROUP(int a,int b),GROUP(a,b))
runtime_subclass_end
它对我来说工作得很好,除了我必须重复参数,一次使用类型(int a, int b
),一次调用底层函数(a,b
)。我想知道是否有更好的方法来做到这一点。
如果您想要删除声明中参数名的冗余(一次在声明列表中与它们的类型一起出现,一次在调用列表中作为名称出现),您可以通过将名称和类型作为两个单独的列表提供,然后使用适当的双参数映射宏将它们压缩在一起来实现。
假设上面是准确的,看起来实际的参数名也不是太重要,所以你可以通过预定义一个虚拟名称列表来进一步简化你的声明,并把它从声明的可见部分中删除:
#define NARGS(...) NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
#define CAT(A, B) CAT_(A, B)
#define CAT_(A, B) A##B
#define ID(...) __VA_ARGS__
#define APPEND(L, E) ID(L),E
#define FIRST(A, ...) A
#define REST(A, ...) __VA_ARGS__
#define ZIP(F, L1, L2) CAT(ZIP_, ID(NARGS L1))(F, L1, L2)
#define ZIP_4(F, L1, L2) F(ID(FIRST L1), ID(FIRST L2)), ZIP_3(F, (ID(REST L1)), (ID(REST L2)))
#define ZIP_3(F, L1, L2) F(ID(FIRST L1), ID(FIRST L2)), ZIP_2(F, (ID(REST L1)), (ID(REST L2)))
#define ZIP_2(F, L1, L2) F(ID(FIRST L1), ID(FIRST L2)), ZIP_1(F, (ID(REST L1)), (ID(REST L2)))
#define ZIP_1(F, L1, L2) F(ID(FIRST L1), ID(FIRST L2))
#define ZIP_0(F, L1, L2)
#define GENSYMS (_0, _1, _2, _3, _4, _5, _6, _7, _8, _9)
#define runtime_subclass_method(Superclass,rtype,method,args)
rtype method(ZIP(EMIT_DECL, args, GENSYMS)) {
if( table.count(#method) == 0 ) return Superclass::method(ZIP(EMIT_CALL, args, GENSYMS));
return table.at(#method)(this, ID(ZIP(EMIT_CALL, args, GENSYMS)));
}
#define EMIT_DECL(T, N) T N
#define EMIT_CALL(T, N) N
runtime_subclass_method(Superclass,int,doSomething,(int,int))
这个例子的大部分是实用程序的东西(如CAT
)。扩展ZIP
, NARGS
和GENSYMS
来接受更多的参数(四个对于实际来说有点小)应该是微不足道的。
方法声明只接受参数类型列表,将它们与声明的预定义列表中的名称压缩在一起,并将长度与名称压缩以生成调用列表。
相关文章:
- 继承期间显示未知行为的子类
- 通过指向指针数组的指针访问子类的属性
- 从父类方法返回子类对象
- c++, 在子类中,如何在没有对象的情况下访问父类的方法?
- 将父类对象强制转换为子类的问题
- 避免在C++中重复子类定义
- 将QOpenGLWidget子类转换为使用Metal而不是OpenGL的子类是否可行?
- 如何初始化矢量的模板化子类
- C++ 继承:将子类传递给需要基类的函数并获取子类行为
- 有没有办法按值将纯抽象类的所有子类传递给 C++ 中的函数?
- 使用子类覆盖基类中定义的函数
- 子类地址等于虚拟基类地址?
- 将子类方法声明为基类的友元
- C++子类共享变量?
- 如何检查模板专用化是否是基本模板的子类?
- 仅让特定类'Fabric'构造类'Foo'及其所有子类的实例
- 如何访问基类向量中的子类变量?(对于实体组件系统)
- 对系统菜单进行子类划分
- 如何做一个运行时子类化系统
- 如何从实体组件系统的子类中访问属性