'typeid' проти 'typeof' в C ++


159

Мені цікаво, в чому різниця між typeidі typeofв C ++. Ось що я знаю:

  • typeidзгадується в документації для type_info, яка визначена у файлі типу infoinfo заголовка C ++ .

  • typeofвизначається в розширенні GCC для C та в бібліотеці Bo + C ++ Boost .

Крім того, ось тест кодового тесту, який я створив там, де виявив, що typeidне повертає те, що я очікував. Чому?

main.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

8
Яким чином ви вважаєте, що ваш код не друкує правильних імен типу? Це мені добре виглядає. Фактична рядок, що повертається, name()визначається реалізацією. Це не повинно бути дійсним ідентифікатором C ++, лише те, що однозначно ідентифікує тип. Схоже, ваша реалізація використовує загальну схему керування іменами компілятора.
Роб Кеннеді

Дякую Роб! Я очікував, що вони точно такі ж, як імена типів, як я бачив у en.wikipedia.org/wiki/Typeid. Що тут можна зробити назви?
Тім

Якщо ви не новачок, як я: Вам потрібна віртуальна функція в базовому типі, щоб увімкнути vtable або останній рядок буде надрукувати базовий тип.
jw_

Відповіді:


200

Мова C ++ не має такого поняття, як typeof. Ви повинні дивитись на якесь компіляторне розширення. Якщо ви говорите про GCC typeof, то подібна функція присутня в C ++ 11 через ключове слово decltype. Знову ж таки, у C ++ немає такого typeofключового слова.

typeid- це оператор мови C ++, який повертає ідентифікаційну інформацію типу під час виконання. Він в основному повертає type_infoоб'єкт, що є рівним порівнянні з іншими type_infoоб'єктами.

Зауважимо, що єдиним визначеним властивістю повернутого type_infoоб'єкта є його порівнянність рівності та нерівності, тобто type_infoоб'єкти, що описують різні типи, повинні порівнювати нерівні, тоді як type_infoоб'єкти, що описують один і той же тип, мають порівнювати рівні. Все інше визначається реалізацією. Методи, які повертають різні "імена", не гарантують повернення нічого, зрозумілого для людини, і навіть не гарантують, що взагалі повернуть щось.

Зауважимо також, що вищезазначене, мабуть, означає (хоча стандарт, схоже, не чітко згадує про це), що послідовні програми одного typeidі того ж типу можуть повертати різні type_infoоб'єкти (які, звичайно, все ж повинні порівнювати рівними).


1
чи не потрібно це оновлення, оскільки C ++ 11 має decltype? Я не впевнений, що таке загальна політика, але, оскільки питання позначене тегом, C++я би очікував, що воно стосується останнього стандарту. Переназначення питання також C++03було б варіантом. Я особисто інколи буваю досить заплутаним, оскільки мені доводиться використовувати preC ++ 11 на роботі, а іноді я не впевнений, що є "pre11" або "post11".
idclev 463035818

11
FYI, decltypeне є заміною typeof. typeofтакож працює на типи, поки decltypeнемає. Наприклад, typeof(int)є intwhile decltype(int)є помилка.
Шахбаз

1
" type_infoоб'єкти, що описують різні типи, повинні порівнювати нерівні" . Насправді це не гарантується . Оператор нерівності був видалений у C ++ 20 - (я припускаю) відштовхуючись, покладаючись на різні типи, порівнюючи нерівні. Але якщо ви задумаєтесь, рівність не є безпечною, якщо нерівність не є безпечною.
Індіана Кернік

51

Основна різниця між ними полягає в наступному

  • typeof - це конструкція часу компіляції та повертає тип, визначений під час компіляції
  • typeid - це конструкція часу виконання, а отже, дає інформацію про тип часу виконання.

typeof Довідка: http://www.delorie.com/gnu/docs/gcc/gcc_36.html

typeid Довідка: https://en.wikipedia.org/wiki/Typeid


Дякую, JaredPar! У мене в оновленому дописі після прочитання ваших відповідей є нові запитання. Наприклад, якщо це правда, що їх повернення використовуються для різних цілей: повернення typeof використовується як ключове слово типу, яке може визначати змінну, але повернення typeid не може?
Тім

26

typeidможе працювати під час виконання та повертати об’єкт, що описує тип часу об'єкта, який повинен бути вказівником на об’єкт класу з віртуальними методами, щоб RTTI (інформація про тип виконання) зберігалася у класі. Він також може дати тип часу компіляції виразу або імені типу, якщо йому не надано вказівник на клас із інформацією про тип часу виконання.

typeofє розширенням GNU і дає вам тип будь-якого виразу під час компіляції. Це може бути корисно, наприклад, для декларування тимчасових змінних у макросах, які можуть бути використані для декількох типів. У C ++ ви зазвичай використовуєте шаблони замість цього.


5
Наскільки я знаю, я typeidприйму будь-який вираз, не тільки той, який оцінює для об'єктів віртуальними методами. Крім того, typeidбуде прийнято ім'я типу , а не лише вираз. Ви можете сказати typeid(5)або typeid(std::string)хочете.
Роб Кеннеді

1
Я уточнив свою відповідь, щоб зробити це зрозумілим; typeid може повернути інформацію про тип часу виконання, якщо вона є, але надасть інформацію про компілювати час для будь-чого іншого.
Брайан Кемпбелл

Дякую, Брайан і Роб! У мене в оновленому дописі після прочитання ваших відповідей є нові запитання.
Тім

22

Відповідь на додаткове запитання:

мій наступний тестовий код для 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.
}

Дякую, Арак! Я щойно оновив публікацію новими запитаннями. Будь ласка, подивіться, якщо можливо.
Тім

4

typeid надає тип даних під час виконання під час запиту. Typedef - це конструкція часу компіляції, яка визначає новий тип, як заявлено після цього. У C ++ вихідний текст не вводиться як тип (відображається як вписані коментарі):

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

3

Ви можете використовувати демангування Boost, щоб досягти гарного вигляду:

#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);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.