[英]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: 以下是我提出并拒绝的一些想法:
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. 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
类型特征之类的实现中。 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. dynamic_cast
) to std::type_info
itself, or someone thought that it was cute, or embarrassing if type_info
wasn't polymorphic. 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? typeid(std::type_info) == typeid(typeid(A))
? typeid(std::type_info) == typeid(typeid(A))
? type_info
, so a portable program wouldn't be able to tell the difference. type_info
上允许的操作集,因此便携式程序将无法执行分辨出来。 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: 但是,如果它被禁止,那么实施可以:
type_info
type_info
某个派生类中 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 fromtype_info
.3 /它
A__type_info
具有自定义类型的元类的可能性 - 每个真正的多态class A
将获得派生的“元类”A__type_info
,它派生自type_info
。 Perhaps such derived classes could expose members that callnew A
with various constructor arguments in a type-safe way, and things like that.也许这样的派生类可以以类型安全的方式公开使用各种构造函数参数调用
new A
成员,以及类似的东西。 But makingtype_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 thetype_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.