什么是处理类的元方面的适当接口?
我正在寻找一些关于处理类(处理类)方面的适当接口的建议,但这些方面不是他们正在处理的实际类的一部分(元-方面)。这需要一些解释...
在我的具体示例中,我需要实现一个自定义 RTTI 系统,该系统比 C++ 提供的系统稍微复杂一点(我不会详细说明为什么需要它)。我的基础对象是 FooBase ,该基础的每个子类都与一个 FooTypeInfo 对象关联。
// Given a base pointer that holds a derived type,
// I need to be able to find the actual type of the
// derived object I'm holding.
FooBase* base = new FooDerived;
// The obvious approach is to use virtual functions...
const FooTypeInfo& info = base->typeinfo();
使用虚函数来处理对象的运行时类型对我来说并不合适。我倾向于认为对象的运行时类型超出了类的范围,因此它不应该是其显式接口的一部分。下面的接口让我感觉更舒服......
FooBase* base = new FooDerived;
const FooTypeInfo& info = foo::typeinfo(base);
但是,即使接口不是类的一部分,实现仍然必须使用虚函数,才能使其工作:
class FooBase
{
protected:
virtual const FooTypeInfo& typeinfo() const = 0;
friend const FooTypeInfo& ::foo::typeinfo(const FooBase*);
};
namespace foo
{
const FooTypeInfo& typeinfo(const FooBase* ptr) {
return ptr->typeinfo();
}
}
你认为我应该使用这个第二个接口(感觉更适合我)并处理稍微复杂的实现,或者我应该使用第一个接口?
@塞斯·卡内基
如果您甚至不希望派生类知道自己是 RTTI 的一部分,那么这就是一个难题...因为您实际上无法在依赖于的
FooBase
构造函数中执行任何操作正在实例化的类的运行时类型(出于同样的原因,您不能在 ctor 或 dtor 中调用虚拟方法)。
FooBase
是层次结构的公共基础。我还有一个单独的 CppFoo<>
类模板,它减少了样板文件的数量并使类型的定义更容易。还有另一个使用 Python 派生对象的 PythonFoo
类。
template<typename FooClass>
class CppFoo : public FooBase
{
private:
const FooTypeInfo& typeinfo() const {
return ::foo::typeinfo<FooClass>();
}
};
class SpecificFoo : public CppFoo<SpecificFoo>
{
// The class can now be implemented agnostic of the
// RTTI system that works behind the scenes.
};
有关系统如何工作的更多详细信息可以在此处找到:
► https://stackoverflow.com/a/8979111/627005
I'm looking for some advice of what would be an appropriate interface for dealing with aspects about classes (that deal with classes), but which are not part of the actual class they are dealing with (meta-aspects). This needs some explanation...
In my specific example I need to implement a custom RTTI system that is a bit more complex than the one offered by C++ (I won't go into why I need that). My base object is FooBase
and each child class of this base is associated a FooTypeInfo
object.
// Given a base pointer that holds a derived type,
// I need to be able to find the actual type of the
// derived object I'm holding.
FooBase* base = new FooDerived;
// The obvious approach is to use virtual functions...
const FooTypeInfo& info = base->typeinfo();
Using virtual functions to deal with the run-time type of the object doesn't feel right to me. I tend to think of the run-time type of an object as something that goes beyond the scope of the class, and as such it should not be part of its explicit interface. The following interface makes me feel a lot more comfortable...
FooBase* base = new FooDerived;
const FooTypeInfo& info = foo::typeinfo(base);
However, even though the interface is not part of the class, the implementation would still have to use virtual functions, in order for this to work:
class FooBase
{
protected:
virtual const FooTypeInfo& typeinfo() const = 0;
friend const FooTypeInfo& ::foo::typeinfo(const FooBase*);
};
namespace foo
{
const FooTypeInfo& typeinfo(const FooBase* ptr) {
return ptr->typeinfo();
}
}
Do you think I should use this second interface (that feels more appropriate to me) and deal with the slightly more complex implementation, or shoud I just go with the first interface?
@Seth Carnegie
This is a difficult problem if you don't even want derived classes to know about being part of the RTTI ... because you can't really do anything in the
FooBase
constructor that depends on the runtime type of the class being instantiated (for the same reason you can't call virtual methods in a ctor or dtor).
FooBase
is the common base of the hierarchy. I also have a separate CppFoo<>
class template that reduces the amount of boilerplate and makes the definition of types easier. There's another PythonFoo
class that work with Python derived objects.
template<typename FooClass>
class CppFoo : public FooBase
{
private:
const FooTypeInfo& typeinfo() const {
return ::foo::typeinfo<FooClass>();
}
};
class SpecificFoo : public CppFoo<SpecificFoo>
{
// The class can now be implemented agnostic of the
// RTTI system that works behind the scenes.
};
A few more details about how the system works can be found here:
► https://stackoverflow.com/a/8979111/627005
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以通过
typeid
关键字将动态类型与静态类型联系起来,并使用返回的std::type_info
对象作为标识方式。此外,如果您将typeid
应用于专门为此目的而创建的单独类,那么对于您感兴趣的类来说,这将是完全非侵入性的,尽管它们的名称仍然必须提前知道。重要的是,typeid
应用于支持动态多态性的类型 - 它必须具有一些virtual
函数。这是一个例子:
不用说,由于
std::type_info
是正确的对象,并且它们是唯一且有序的,因此您可以在集合中管理它们,从而删除从接口查询的类型:当然可以按照您认为合适的方式混合搭配两者。
有两个限制:
一种可能的变化是添加 RTTI“框架钩子”,例如
static constsensor。 rtti_MyClass;
到类名已知的实现文件,并让构造函数完成工作。此时它们还必须是完整的类型,才能在传感器中进行内省。You can tie dynamic type with static type via
typeid
keyword and use returnedstd::type_info
objects as means of identification. Furthermore, if you applytypeid
on a separate class created specially for the purpose, it will be totally non-intrusive for the classes you are interesed in, althought their names still have to be known in advance. It is important thattypeid
is applied on a type which supports dynamic polymorphism - it has to have somevirtual
function.Here is example:
Needless to say, since
std::type_info
are proper objects and they are unique and ordered, you can manage them in a collection and thus erase type queried from the interface:Of course you can mix and match both, as you see fit.
Two limitations:
template struct sensor
via clever metaprogramming, it's very wide subject (and mind bending, sometimes).One possible variation is adding RTTI "framework hook" such as
static const sensor<Myclass> rtti_MyClass;
to implementation files where class names are already known and let the constructor do the work. They would also have to be complete types at this point to enable introspection in sensor.