有什么原因 std::type_info 指定是多态的吗?驱动器被指定为虚拟的(并且在C ++的设计和演变中对“这样的效果”有评论)。我真的看不到令人信服的原因。我没有任何特定用例,我只是想知道它背后是否有理由或故事。


这是我想出并拒绝的一些想法:

  1. 这是一个可扩展的点 - 实现可能定义子类,然后程序可能会尝试 dynamic_cast 一种 std::type_info 对于另一个实现定义的派生类型。这可能是原因,但是对于实施添加实现定义的成员似乎同样容易,这可能是虚拟的。无论如何,希望测试这些扩展的程序必然是不可存储的。
  2. 这是为了确保在 delete为基本指针。但是没有标准派生类型,用户无法定义有用的派生类型,因为 type_info 没有标准的公共构造师,所以 deletea type_info 指针绝不是合法和便携式的。而且派生类型没有用,因为它们无法构造 - 我知道这种非结构性派生类型的唯一用法是在实现之类的事物中 is_polymorphic 类型特征。
  3. 它打开了具有定制类型的元类的可能性 - 每种真实多态性 class A 会得到衍生的“元类” A__type_info, ,源自 type_info. 。也许这种派生的课程可能会暴露出来的成员 new A 以各种构造函数为类型的构造词以及类似的方式。但是制作 type_info 多态性本身实际上使一个想法基本上不可能实现,因为您必须拥有元素的元素,即ad infinitum,这是一个问题 type_info 对象具有静态存储持续时间。也许除非这是使其多态的原因。
  4. 有一些用于应用RTTI功能的用途(除了 dynamic_cast) 到 std::type_info 本身,或者有人认为它很可爱,或者很尴尬 type_info 不是多态。但是,鉴于没有标准类型,并且在标准层次结构中没有其他类别可以合理地尝试交叉播,问题是:什么?是否有表达方式 typeid(std::type_info) == typeid(typeid(A))?
  5. 这是因为实施者将创建自己的私人派生类型(我相信GCC确实如此)。但是,为什么要打扰它呢?即使未指定攻击器为虚拟,并且实施者决定应该是虚拟的,肯定可以将其声明为虚拟,因为它不会更改允许的操作集 type_info, ,因此便携式程序无法分辨出区别。
  6. 这与具有部分兼容的ABI共存的编译器有关,这可能是由于动态链接而导致的。也许实施者可以认识自己的 type_info 如果以便携式方式(与另一个供应商起源于另一个供应商)的子类(相反) type_info 保证是虚拟的。

目前,最后一个对我来说是最合理的,但这很虚弱。

有帮助吗?

解决方案

我认为它是为了方便实施者的。它允许他们定义扩展 type_info 上课,并通过指针删除它们 type_info 在程序退出时,无需在特殊的编译器魔术中构建才能调用正确的破坏者,或者以其他方式跳过篮球。

当然,实现可以将其声明为虚拟,因为它不会更改type_info上允许的操作集,因此便携式程序将无法分辨出差异。

我认为这不是真的。考虑以下:

#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);
}

是否是 合理的 是否允许使用第一个动态铸件(并评估为空指针),而第二个动态铸件则不允许。因此,如果 type_info 在标准中定义为具有默认的非虚拟驱动器,但实现添加了虚拟驱动器,然后便携式程序可以分辨出差异[*]。

对我来说,将虚拟破坏者置于标准方面似乎比以下两个方面更简单:

a)在标准中提到的注释,尽管班级定义暗示着 type_info 没有虚拟函数,可以具有虚拟驱动器。

b)确定可以区分是否存在的程序集 type_info 是否是多态性的,并禁止所有这些。我不知道它们可能不是很有用或有效的程序,但是要禁止它们,您必须提出一些标准语言,这些语言描述了您对正常规则的特定例外。

因此,我认为标准必须要求虚拟驱动器或禁止它。使它的可选化太复杂了(或者我应该说,我认为这将被认为是不必要的复杂。复杂性从未阻止标准委员会在被认为是值得的地区...)

但是,如果被禁止,则可以实施:

  • 将虚拟破坏者添加到某些派生的类别 type_info
  • 班级
  • 在内部将其用作多态基类

这将解决我在帖子顶部描述的情况, 静态类型 typeid 表达仍然是 const std::type_info, ,因此实施将很难定义程序可以在其中可以 dynamic_cast 到各种目标,看看哪种 type_info 他们在特定情况下拥有的对象。也许标准希望允许这样做,尽管实施始终可以提供 typeid 使用不同的静态类型,或保证 static_cast 到某个扩展程序类将起作用,然后让程序 dynamic_cast 从那里。

总而言之,据我所知,虚拟破坏者对实施者有可能有用,并且除了它没有任何其他任何事情,除了我们不会花时间想知道它为什么在那里;-)

*]实际上,我没有证明这一点。我证明了一个非法计划,所有其他程序都是平等的。但是,实现可能会通过确保所有人不平等,并且不编译。 Boost is_polymorphic 无法便携,因此虽然可以测试一个课程 多态,应该是,一个符合程序可能无法测试该课程 不是 多态,那不应该。我认为,即使是不可能的,也证明,为了从标准中删除一行,这是很多努力。

其他提示

C ++标准说 typeid 返回类型type_info的对象或实现定义的子类。所以...我想这几乎是答案。因此,我不明白您为什么拒绝您的分1和2。

当前C ++标准的第5.2.8段第1条读取:

typeID表达式的结果是静态类型const std :: type_info(18.5.1)和动态类型const std :: type_info或const名称的lvalue,其中名称是std :: type_info的实现定义的类在18.5.1.61中描述的行为)LVALUE所指对象的寿命扩展到程序的末尾。未指定的在程序末尾的type_info对象调用destructor是否被调用。

反过来,这意味着可以编写以下代码是合法和良好的:const type_info& x = typeid(expr); 可能需要该类型为多态性

关于您在C ++中可以拥有的最简单的“全局” ID是一个类名称,并且 typeinfo 提供了一种比较此ID的方法以保持平等。但是设计是如此尴尬和有限,以至于您需要包装 typeinfo 在某些包装班中,例如能够将实例放入集合中。 Andrei Alexandrescu在他的“现代C ++设计”中做到了这一点,我认为 typeinfo 包装器是Loki图书馆的一部分;可能也有一个。而且自己滚动很容易,例如,请参阅 我自己的包装纸.

但是,即使对于这样的包装纸,一般都没有任何虚拟灾难中的 typeinfo.

因此,这个问题不是那么“嗯,为什么有虚拟灾难”,而是,正如我所看到的,“嗯,为什么设计如此落后,尴尬且不直接可用”?我将其归结为标准化过程。例如,iostreams也不是精美设计的示例。没有什么要效仿的。

3/它留下了具有定制类型的元类的可能性 - 每种真实多态性 class A 会得到衍生的“元类” A__type_info, ,源自 type_info. 。也许这种派生的课程可能会暴露出来的成员 new A 以各种构造函数为类型的构造词以及类似的方式。但是制作 type_info 多态性本身实际上使一个想法基本上不可能实现,因为您必须拥有元素的元素,即ad infinitum,这是一个问题 type_info 对象具有静态存储持续时间。也许除非这是使其多态的原因。

聪明的...

无论如何,我不同意这种推理:此类实施可以轻松排除从 type_info, , 包含 type_info 本身。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top