【问题标题】:'typeid' versus 'typeof' in C++C ++中的'typeid'与'typeof'
【发布时间】:2010-12-31 11:32:20
【问题描述】:

我想知道 C++ 中 typeidtypeof 之间有什么区别。以下是我所知道的:

  • type_info 的文档中提到了typeid,该文档在 C++ 头文件 typeinfo 中定义。

  • typeof 在 C 的 GCC 扩展和 C++ Boost 库中定义。

另外,这是我创建的测试代码测试,我发现typeid 没有返回我预期的结果。为什么?

ma​​in.cpp

#include <iostream>  
#include <typeinfo>  //for 'typeid' to work  

class Person {  
    public:
    // ... Person members ...  
    virtual ~Person() {}  
};  

class Employee : public Person {  
    // ... Employee members ...  
};  

int main () {  
    Person person;  
    Employee employee;  
    Person *ptr = &employee;  
    int t = 3;  

    std::cout << typeid(t).name() << std::endl;  
    std::cout << typeid(person).name() << std::endl;   // Person (statically known at compile-time)  
    std::cout << typeid(employee).name() << std::endl; // Employee (statically known at compile-time)  
    std::cout << typeid(ptr).name() << std::endl;      // Person * (statically known at compile-time)  
    std::cout << typeid(*ptr).name() << std::endl;     // Employee (looked up dynamically at run-time  
                                                       // because it is the dereference of a pointer
                                                       // to a polymorphic class)  
 }  

输出:

bash-3.2$ g++ -Wall main.cpp -o main  
bash-3.2$ ./main   
i  
6Person  
8Employee  
P6Person  
8Employee

【问题讨论】:

  • 您认为您的代码以何种方式无法打印正确的类型名称?对我来说看起来不错。 name() 返回的实际字符串是实现定义的。它不必是有效的 C++ 标识符名称,只要是唯一标识类型的 something 即可。看起来您的实现使用了编译器的通用名称修饰方案。
  • 谢谢罗伯!我期望那些与我在 en.wikipedia.org/wiki/Typeid 中看到的类型名称完全相同。名称修改在这里可以做什么?
  • 如果你像我一样是 typeid 新手:你需要在基类型中有一个虚函数来开启 vtable 否则最后一行会打印基类型。

标签: c++ typeof typeid


【解决方案1】:

C++ 语言没有typeof 这样的东西。您必须查看一些特定于编译器的扩展。如果您谈论的是 GCC 的 typeof,那么 C++11 中通过关键字 decltype 提供了类似的功能。同样,C++ 没有这样的 typeof 关键字。

typeid 是一个 C++ 语言运算符,它在运行时返回类型标识信息。它基本上返回一个type_info 对象,该对象与其他type_info 对象具有同等可比性。

注意,返回的type_info 对象的唯一定义属性是它是相等和不相等可比较的,即描述不同类型的type_info 对象应该比较不相等,而描述的type_info 对象相同的类型必须比较相等。其他一切都是实现定义的。返回各种“名称”的方法不保证返回任何人类可读的内容,甚至根本不保证返回任何内容。

还要注意,上面可能暗示(尽管标准似乎没有明确提及)typeid 对同一类型的连续应用可能会返回不同的type_info 对象(当然,仍然有比较相等)。

【讨论】:

  • 这是否需要更新,因为 C++11 有 decltype ?我不确定一般政策是什么,但由于问题标记为C++,我希望它参考最新标准。将问题重新标记为C++03 也是一个选项恕我直言。我个人有时会很困惑,因为我必须在工作中使用 preC++11,有时我不确定什么是真正的“pre11”或“post11”。
  • 仅供参考,decltype 不能替代 typeoftypeof 也适用于类型,而 decltype 不适用。例如,typeof(int)intdecltype(int) 是一个错误。
  • "type_info 描述不同类型的对象应比较不相等"。实际上,这个isn't guaranteed。不等式运算符是removed in C++20(我假设)不鼓励依赖比较不相等的不同类型。但如果你仔细想想,如果不平等不安全,平等也不安全。
【解决方案2】:

两者的主要区别如下

  • typeof 是一个编译时构造,返回编译时定义的类型
  • typeid 是一个运行时构造,因此提供有关值的运行时类型的信息。

类型参考:http://www.delorie.com/gnu/docs/gcc/gcc_36.html

typeid 参考:https://en.wikipedia.org/wiki/Typeid

【讨论】:

  • 谢谢你,贾里德帕!阅读您的回复后,我在更新后的帖子中有一些新问题。比如如果它们的返回用于不同的目的也是如此:typeof的返回用作可以定义变量的类型关键字,但typeid的返回不能?
  • 第一个链接已失效(发送至gnu.org)。
【解决方案3】:

typeid可以在运行时操作,并返回一个描述对象运行时类型的对象,该对象必须是指向具有虚方法的类的对象的指针,以便RTTI (run-time type information)存储在类中.如果没有给出指向具有运行时类型信息的类的指针,它还可以给出表达式的编译时类型或类型名称。

typeof 是一个 GNU 扩展,并在编译时为您提供任何表达式的类型。这可能很有用,例如,在可用于多种类型的宏中声明临时变量时。在 C++ 中,您通常会使用 templates

【讨论】:

  • 据我所知,typeid 将接受任何表达式,而不仅仅是那些使用虚方法计算对象的表达式。此外,typeid 将接受类型 name,而不仅仅是表达式。如果你愿意,你可以说typeid(5)typeid(std::string)
  • 我已经澄清了我的答案以明确这一点; typeid可以返回运行时类型信息(如果可用),但将为其他任何内容提供编译时类型信息。
  • 谢谢你,Brian 和 Rob!阅读您的回复后,我在更新后的帖子中有一些新问题。
【解决方案4】:

回答附加问题:

我的以下 typeid 测试代码确实 不输出正确的类型名称。 怎么了?

没有任何问题。您看到的是类型名称的字符串表示形式。标准 C++ 并不强制编译器发出类的确切名称,它只是由实现者(编译器供应商)来决定什么是合适的。简而言之,名称由编译器决定。


这是两种不同的工具。 typeof 返回表达式的类型,但它不是标准的。在 C++0x 中,有一个叫做 decltype 的东西在 AFAIK 中做同样的工作。

decltype(0xdeedbeef) number = 0; // number is of type int!
decltype(someArray[0]) element = someArray[0];

typeid 用于多态类型。例如,假设cat 派生animal

animal* a = new cat; // animal has to have at least one virtual function
...
if( typeid(*a) == typeid(cat) )
{
    // the object is of type cat! but the pointer is base pointer.
}

【讨论】:

  • 谢谢你,阿拉克!我刚刚用一些新问题更新了帖子。如果可能,请看一下。
【解决方案5】:

typeid 在运行时根据要求提供数据的类型。 Typedef 是一个编译时构造,它定义了一个新类型,如下所述。 C++ 中没有 typeof 输出显示为(显示为内切 cmets):

std::cout << typeid(t).name() << std::endl;  // i
std::cout << typeid(person).name() << std::endl;   // 6Person
std::cout << typeid(employee).name() << std::endl; // 8Employee
std::cout << typeid(ptr).name() << std::endl;      // P6Person
std::cout << typeid(*ptr).name() << std::endl;     //8Employee

【讨论】:

    【解决方案6】:

    您可以使用 Boost demangle 来完成一个好看的名称:

    #include <boost/units/detail/utility.hpp>
    

    类似的东西

    To_main_msg_evt ev("Failed to initialize cards in " + boost::units::detail::demangle(typeid(*_IO_card.get()).name()) + ".\n", true, this);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-28
      • 1970-01-01
      • 1970-01-01
      • 2011-07-20
      相关资源
      最近更新 更多