简体   繁体   English

为什么std :: type_info是多态的?

[英]Why is std::type_info polymorphic?

Is there a reason why std::type_info is specified to be polymorphic? 是否有理由将std::type_info指定为多态? The destructor is specified to be virtual (and there's a comment to the effect of "so that it's polymorphic" in The Design and Evolution of C++). 析构函数被指定为虚拟(并且在“C ++的设计和演变”中对“因此它是多态的”效果进行了评论)。 I can't really see a compelling reason why. 我真的没有看到令人信服的理由。 I don't have any specific use case, I was just wondering if there ever was a rationale or story behind it. 我没有任何具体的用例,我只是想知道它背后是否有任何理由或故事。


Here's some ideas that I've come up with and rejected: 以下是我提出并拒绝的一些想法:

  1. It's an extensibility point - implementations might define subclasses, and programs might then try to dynamic_cast a std::type_info to another, implementation-defined derived type. 它是一个可扩展点 - 实现可能会定义子类,然后程序可能会尝试将std::type_info dynamic_cast为另一个实现定义的派生类型。 This is possibly the reason, but it seems that it's just as easy for implementations to add an implementation-defined member, which could possibly be virtual. 这可能是原因,但似乎实现添加实现定义的成员(可能是虚拟的)也很容易。 Programs wishing to test for these extensions would necessarily be non-portable anyway. 希望测试这些扩展的程序无论如何都必然是不可移植的。
  2. It's to ensure that derived types are destroyed properly when delete ing a base pointer. 这是为了确保在delete基指针时正确销毁派生类型。 But there are no standard derived types, users can't define useful derived types, because type_info has no standard public constructors, and so delete ing a type_info pointer is never both legal and portable. 但是没有标准的派生类型,用户无法定义有用的派生类型,因为type_info没有标准的公共构造函数,因此delete type_info指针绝不是合法的和可移植的。 And the derived types aren't useful because they can't be constructed - the only use I know for such non-constructible derived types is in the implementation of things like the is_polymorphic type trait. 并且派生类型没有用,因为它们无法构造 - 我知道这种非可构造派生类型的唯一用途是在is_polymorphic类型特征之类的实现中。
  3. It leaves open the possibility of metaclasses with customized types - each real polymorphic class A would get a derived "metaclass" A__type_info , which derives from type_info . A__type_info具有自定义类型的元类的可能性 - 每个真正的多态class A将获得派生的“元类” A__type_info ,它派生自type_info Perhaps such derived classes could expose members that call new A with various constructor arguments in a type-safe way, and things like that. 也许这样的派生类可以以类型安全的方式公开使用各种构造函数参数调用new A成员,以及类似的东西。 But making type_info polymorphic itself actually makes such an idea basically impossible to implement, because you'd have to have metaclasses for your metaclasses, ad infinitum, which is a problem if all the type_info objects have static storage duration. 但是使type_info多态本身实际上使得这样的想法基本上不可能实现,因为你必须为你的元类提供元类,无限制,如果所有的type_info对象都有静态存储持续时间,这就是一个问题。 Maybe barring this is the reason for making it polymorphic. 也许禁止这是使其变为多态的原因。
  4. There's some use for applying RTTI features (other than dynamic_cast ) to std::type_info itself, or someone thought that it was cute, or embarrassing if type_info wasn't polymorphic. 有一些用于将RTTI功能(除了dynamic_cast )应用于std::type_info本身,或者有人认为它很可爱,或者如果type_info不是多态的则令人尴尬。 But given that there's no standard derived type, and no other classes in the standard hierarchy which one might reasonably try cross-cast to, the question is: what? 但鉴于没有标准派生类型,并且标准层次结构中没有其他类可以合理地尝试交叉投射,问题是:什么? Is there a use for expressions such as typeid(std::type_info) == typeid(typeid(A)) ? 是否有用于表达式,如typeid(std::type_info) == typeid(typeid(A))
  5. It's because implementers will create their own private derived type (as I believe GCC does). 这是因为实施者将创建他们自己的私有派生类型(我相信GCC会这样做)。 But, why bother specifying it? 但是,为什么还要指定它呢? Even if the destructor wasn't specified as virtual and an implementer decided that it should be, surely that implementation could declare it virtual, because it doesn't change the set of allowed operations on type_info , so a portable program wouldn't be able to tell the difference. 即使析构函数未被指定为虚拟,并且实现者决定它应该是,但是实现可以将其声明为虚拟,因为它不会更改type_info上允许的操作集,因此便携式程序将无法执行分辨出来。
  6. It's something to do with compilers with partially compatible ABIs coexisting, possibly as a result of dynamic linking. 这与部分兼容的ABI共存的编译器有关,可能是动态链接的结果。 Perhaps implementers could recognize their own type_info subclass (as opposed to one originating from another vendor) in a portable way if type_info was guaranteed to be virtual. 如果确保type_info是虚拟的,那么实现者可以以可移植的方式识别他们自己的type_info子类(而不是源自另一个供应商的子类)。

The last one is the most plausible to me at the moment, but it's pretty weak. 最后一个对我来说是最合理的,但它相当弱。

The C++ standard says that typeid returns an object of type type_info, OR AN IMPLEMENTATION-DEFINED subclass thereof. C ++标准说typeid返回一个type_info类型的对象,或者它的一个IMPLEMENTATION-DEFINED子类。 So... I guess this is pretty much the answer. 所以...我想这几乎就是答案。 So I don't see why you reject your points 1 and 2. 所以我不明白为什么你拒绝你的第1点和第2点。

Paragraph 5.2.8 Clause 1 of the current C++ standard reads: 第5.2.8段当前C ++标准第1条规定:

The result of a typeid expression is an lvalue of static type const std::type_info (18.5.1) and dynamic type const std::type_info or const name where name is an implementation-defined class derived from std::type_info which preserves the behavior described in 18.5.1.61) The lifetime of the object referred to by the lvalue extends to the end of the program. typeid表达式的结果是静态类型const std :: type_info(18.5.1)和动态类型const std :: type_info或const name的左值,其中name是从std :: type_info派生的实现定义类,它保留了18.5.1.61中描述的行为)左值引用的对象的生命周期延伸到程序的末尾。 Whether or not the destructor is called for the type_info object at the end of the program is unspecified. 是否在程序末尾为type_info对象调用析构函数是未指定的。

Which in turn means that one could write the following code is legal and fine: const type_info& x = typeid(expr); 这反过来意味着可以编写以下代码是合法的和正常的: const type_info& x = typeid(expr); which may require that type_info be polymorphic 这可能要求type_info是多态的

I assume it's there for the convenience of implementers. 我认为这是为了方便实施者。 It allows them to define extended type_info classes, and delete them through pointers to type_info at program exit, without having to build in special compiler magic to call the correct destructor, or otherwise jump through hoops. 它允许它们定义扩展的type_info类,并通过在程序出口处指向type_info指针来删除它们,而不必构建特殊的编译器魔法来调用正确的析构函数,或以其他方式跳过箍。

surely that implementation could declare it virtual, because it doesn't change the set of allowed operations on type_info, so a portable program wouldn't be able to tell the difference. 当然,实现可以将其声明为虚拟,因为它不会更改type_info上允许的操作集,因此便携式程序无法区分它们。

I don't think that's true. 我认为这不是真的。 Consider the following: 考虑以下:

#include <typeinfo>

struct A {
    int x;
};

struct B {
    int x;
};

int main() {
    const A *a1 = dynamic_cast<const A*>(&typeid(int));
    B b;
    const A *a2 = dynamic_cast<const A*>(&b);
}

Whether it's reasonable or not, the first dynamic cast is allowed (and evaluates to a null pointer), whereas the second dynamic cast is not allowed. 无论是否合理 ,都允许第一个动态转换(并且计算为空指针),而不允许第二个动态转换。 So, if type_info was defined in the standard to have the default non-virtual destructor, but an implementation added a virtual destructor, then a portable program could tell the difference[*]. 因此,如果在标准中定义了type_info以获得默认的非虚拟析构函数,但实现添加了一个虚拟析构函数,那么便携式程序可以区分[*]。

Seems simpler to me to put the virtual destructor in the standard, than to either: 将虚拟析构函数放入标准中似乎比我更简单:

a) put a note in the standard that, although the class definition implies that type_info has no virtual functions, it is permitted to have a virtual destructor. a)在标准中type_info ,虽然类定义暗示type_info没有虚函数,但允许有虚拟析构函数。

b) determine the set of programs which can distinguish whether type_info is polymorphic or not, and ban them all. b)确定可以区分type_info是否是多态的程序集,并禁止所有程序。 They may not be very useful or productive programs, I don't know, but to ban them you have to come up with some standard language that describes the specific exception you're making to the normal rules. 它们可能不是非常有用或高效的程序,我不知道,但是为了禁止它们,你必须提出一些标准语言来描述你对正常规则所做的具体例外。

Therefore I think that the standard has to either mandate the virtual destructor, or ban it. 因此,我认为标准必须要么强制虚拟析构函数,要么禁止它。 Making it optional is too complex (or perhaps I should say, I think it would be judged unnecessarily complex. Complexity never stopped the standards committee in areas where it was considered worthwhile...) 使其成为可选项太复杂了(或者我应该说,我认为它将被判断为不必要的复杂。复杂性从未阻止标准委员会在其认为值得的领域......)

If it was banned, though, then an implementation could: 但是,如果它被禁止,那么实施可以:

  • add a virtual destructor to some derived class of type_info 将一个虚拟析构函数添加到type_info某个派生类中
  • derive all of its typeinfo objects from that class 获得所有所属类别的对象从该类
  • use that internally as the polymorphic base class for everything 在内部使用它作为一切的多态基类

that would solve the situation I described at the top of the post, but the static type of a typeid expression would still be const std::type_info , so it would be difficult for implementations to define extensions where programs can dynamic_cast to various targets to see what kind of type_info object they have in a particular case. 这将解决我在帖子顶部描述的情况, 但是 typeid表达式的静态类型仍然是const std::type_info ,因此实现很难定义扩展程序,其中程序可以dynamic_cast到各种目标来查看在特定情况下它们具有什么类型的type_info对象。 Perhaps the standard hoped to allow that, although an implementation could always offer a variant of typeid with a different static type, or guarantee that a static_cast to a certain extension class will work, and then let the program dynamic_cast from there. 也许标准希望允许这样做,尽管实现总是可以提供具有不同静态类型的typeid的变体,或者保证static_cast到某个扩展类将起作用,然后让程序dynamic_cast从那里开始。

In summary, as far as I know the virtual destructor is potentially useful to implementers, and removing it doesn't gain anyone anything other than that we wouldn't be spending time wondering why it's there ;-) 总之,据我所知,虚拟析构函数对实现者来说可能是有用的,删除它并没有获得任何除此之外的任何东西我们不会花时间想知道为什么它在那里;-)

[*] Actually, I haven't demonstrated that. [*]实际上,我没有证明这一点。 I've demonstrated that an illegal program would, all else being equal, compile. 我已经证明,在其他条件相同的情况下,非法程序会编译。 But an implementation could perhaps work around that by ensuring that all isn't equal, and that it doesn't compile. 但是,通过确保所有不相等并且不能编译,实现可能可以解决这个问题。 Boost's is_polymorphic isn't portable, so while it's possible for a program to test that a class is polymorphic, that should be, there may be no way for a conforming program to test that a class isn't polymorphic, that shouldn't be. Boost的is_polymorphic是不可移植的,所以虽然程序可以测试一个类多态的,但应该是,一致的程序可能没有办法测试一个类不是多态的,不应该是。 I think though that even if it's impossible, proving that, in order to remove one line from the standard, is quite a lot of effort. 我认为即使这是不可能的,但要证明,为了从标准中删除一行,需要付出相当大的努力。

About the simplest "global" id you can have in C++ is a class name,and typeinfo provides a way to compare such id's for equality. 关于C ++中最简单的“全局”id是类名,而typeinfo提供了一种比较这种id的相等性的方法。 But the design is so awkward and limited that you then need to wrap typeinfo in some wrapper class, eg to be able to put instances in collections. 但是设计是如此笨拙且有限,以至于您需要在某个包装类中包装typeinfo ,例如,以便能够将实例放入集合中。 Andrei Alexandrescu did that in his "Modern C++ Design" and I think that that typeinfo wrapper is part of the Loki library; Andrei Alexandrescu在他的“现代C ++设计”中做到了这typeinfo ,我认为那个typeinfo包装器是Loki库的一部分; there's probably one also in Boost; Boost中可能还有一个; and it's pretty easy to roll your own, eg see my own wrapper . 并且很容易推出自己的,例如看我自己的包装

But even for such a wrapper there's not in general any need for a virtual destructor in typeinfo . 但即使对于这样的包装器,通常也不需要在typeinfo使用虚拟析构typeinfo

The question is therefore not so much "huh, why is there a virtual destructor" but rather, as I see it, "huh, why is the design so backward, awkward and not directly usable"? 因此问题不在于“嗯,为什么会有一个虚拟的析构函数”而是,正如我所看到的那样,“嗯,为什么设计如此落后,笨拙而且不能直接使用”? And I'd put that down to the standardization process. 我将其归结为标准化过程。 For example, iostreams are not exactly examples of superb design, either; 例如,iostreams也不是精湛设计的例子; not something to emulate. 不是模仿的东西。

3/ It leaves open the possibility of metaclasses with customized types - each real polymorphic class A would get a derived "metaclass" A__type_info , which derives from type_info . 3 /它A__type_info具有自定义类型的元类的可能性 - 每个真正的多态class A将获得派生的“元类” A__type_info ,它派生自type_info Perhaps such derived classes could expose members that call new A with various constructor arguments in a type-safe way, and things like that. 也许这样的派生类可以以类型安全的方式公开使用各种构造函数参数调用new A成员,以及类似的东西。 But making type_info polymorphic itself actually makes such an idea basically impossible to implement, because you'd have to have metaclasses for your metaclasses, ad infinitum, which is a problem if all the type_info objects have static storage duration. 但是使type_info多态本身实际上使得这样的想法基本上不可能实现,因为你必须为你的元类提供元类,无限制,如果所有的type_info对象都有静态存储持续时间,这就是一个问题。 Maybe barring this is the reason for making it polymorphic. 也许禁止这是使其变为多态的原因。

Clever... 聪明...

Anyway, I disagree with this reasoning: such implementation could easily rule-out meta classes for types derived from type_info , including type_info itself. 无论如何,我不同意这种推理:这样的实现可以很容易地排除从type_info派生的类的元类,包括type_info本身。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM