C ++ 'da' typeof 'yerine' typeid '


159

C ++ arasında typeidve typeofarasındaki farkın ne olduğunu merak ediyorum . İşte bildiklerim:

  • typeidC ++ başlık dosyası typeinfo'da tanımlanan type_info belgelerinde belirtilmiştir .

  • typeofC için GCC uzantısında ve C ++ Boost kütüphanesinde tanımlanır.

Ayrıca, burada, typeidbeklediğim şeyi döndürmediğini keşfettiğim yerde oluşturduğum test kodu testi . Neden?

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

çıktı:

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

8
Sizce kodunuz doğru tür adlarını basmıyor mu? Bana iyi geliyor. Tarafından döndürülen gerçek dize name(), uygulama tanımlıdır. Geçerli bir C ++ tanımlayıcı adı olmak zorunda değildir, yalnızca türü benzersiz olarak tanımlayan bir şeydir . Uygulamanızın derleyicinin genel ad yönetimi düzenini kullandığı anlaşılıyor.
Rob Kennedy

Teşekkürler Rob! Bunları tam olarak aynı is.wikipedia.org/wiki/Typeid'de gördüğüm adlarla bekliyordum. İsim yönetimi burada ne yapabilir?
Tim

Benim gibi yazmak için yeniyseniz: Vtable'ı açmak için taban türünde sanal bir işleve ihtiyacınız vardır, aksi takdirde son satır taban türünü yazdırır.
jw_

Yanıtlar:


200

C ++ dili diye bir şey yoktur typeof. Derleyiciye özgü bir uzantıya bakmanız gerekir. GCC'lerden bahsediyorsanız typeof, benzer bir özellik C ++ 11'de anahtar kelime aracılığıyla bulunur decltype. Yine, C ++ 'ın böyle bir typeofanahtar kelimesi yoktur .

typeidçalışma zamanında tür tanımlama bilgilerini döndüren bir C ++ dil operatörüdür. Temel olarak type_info, diğer type_infonesnelerle eşitlikle karşılaştırılabilir bir nesne döndürür .

Döndürülen type_infonesnenin tek tanımlı özelliğinin eşitlik ve eşitlikle karşılaştırılamaz olması, yani type_infofarklı türleri tanımlayan nesneler eşit olmayan karşılaştırırken type_info, aynı türü açıklayan nesneler eşit karşılaştırmalıdır. Diğer her şey uygulama tanımlıdır. Çeşitli "isimleri" döndüren yöntemlerin insan tarafından okunabilen herhangi bir şeyi döndürmesi garanti edilmez ve hatta hiçbir şeyi döndürmesi garanti edilmez.

Ayrıca, yukarıdakilerin muhtemelen (standardın açıkça bahsetmese de) typeidaynı türden ardışık uygulamaların farklı type_infonesneler (elbette yine de eşit karşılaştırması gerekir) döndüğünü ima ettiğini unutmayın .


1
C ++ 11 beri bu bir güncelleme gerekmez decltypemi? Genel politikanın ne olduğundan emin değilim, ancak soru etiketlendiğinden C++en son standarda başvurmasını beklerdim. Soruyu yeniden etiketlemek imho için C++03de bir seçenek olacaktır. Ben iş yerinde preC ++ 11 kullanmak zorunda ve bazen gerçek "pre11" veya "post11" ne olduğundan emin değilim, bazen oldukça karışık olsun.
idclev 463035818

11
FYI, decltypeyerine geçmez typeof. typeoftürleri üzerinde de çalışır decltype, değil. Örneğin typeof(int), intwhile decltype(int)bir hatadır.
Shahbaz

1
msgstr " type_infofarklı türleri tanımlayan nesneler eşit olmayanları karşılaştırmalıdır" . Aslında, bu garanti edilmez . Eşitsizlik operatörü, C ++ 20'de , eşit olmayanları karşılaştırarak farklı türlere dayanarak cesaret kırmak için (sanırım) kaldırıldı . Fakat düşünürseniz, eşitsizlik güvenli değilse eşitlik güvenli değildir.
Indiana Kernick

51

İkisi arasındaki birincil fark şudur:

  • typeof bir derleme zamanı yapısıdır ve türü derleme zamanında tanımlandığı gibi döndürür
  • typeid bir çalışma zamanı yapısıdır ve bu nedenle değerin çalışma zamanı türü hakkında bilgi verir.

typeof Reference: http://www.delorie.com/gnu/docs/gcc/gcc_36.html

typeid Başvurusu: https://en.wikipedia.org/wiki/Typeid


Teşekkürler, JaredPar! Yanıtlarınızı okuduktan sonra güncellenmiş yayında yeni sorularım var. Geri dönüşlerinin farklı amaçlar için kullanıldığı da doğrudur: typeof ifadesinin dönüşü, değişkeni tanımlayabilen type anahtar sözcüğü olarak kullanılır, ancak typeid ifadesinin dönüşü kullanılamaz mı?
Tim

26

typeidçalışma zamanında çalışabilir ve sınıfta RTTI (çalışma zamanı türü bilgileri) sınıfında saklanabilmesi için sanal yöntemlerle bir sınıfın nesnesine bir işaretçi olması gereken nesnenin çalışma zamanı türünü açıklayan bir nesneyi döndürebilir . Ayrıca, çalışma zamanı türü bilgisine sahip bir sınıfa işaretçi verilmezse, bir ifadenin derleme zamanı türünü veya tür adını verebilir.

typeofbir GNU oluşumudur ve derleme zamanında herhangi bir ifadenin türünü verir. Bu, örneğin, birden çok türde kullanılabilen makrolarda geçici değişkenler bildirilmesinde yararlı olabilir. C ++ 'da, genellikle şablonlar kullanırsınız.


5
Bildiğim kadarıyla typeid, sadece sanal yöntemlerle nesnelere değer veren ifadeleri değil, herhangi bir ifadeyi kabul edecektir. Ayrıca, yalnızca bir ifade değil, typeidbir tür adı da kabul eder. Sen söyleyebiliriz typeid(5)ya typeid(std::string)isterseniz.
Rob Kennedy

1
Bunu netleştirmek için cevabımı açıkladım; typeid olabilir Varsa çalışma zamanlı tipi bilgileri döndürmek, ancak başka bir şey için derleme zamanı tür bilgi verecektir.
Brian Campbell

Teşekkürler, Brian ve Rob! Yanıtlarınızı okuduktan sonra güncellenmiş yayında bazı yeni sorularım var.
Tim

22

Ek soruyu cevaplama:

typeid için aşağıdaki test kodum doğru tür adını vermiyor. Sorun nedir?

Yanlış bir şey yok. Gördüğünüz, tür adının dize temsilidir. Standart C ++ derleyicileri sınıfın tam adını vermeye zorlamaz, neyin uygun olduğuna karar vermek için uygulayıcıya (derleyici satıcısı) bağlıdır. Kısacası, isimler derleyiciye kalmış.


Bunlar iki farklı araçtır. typeofifadenin türünü döndürür, ancak standart değildir. C ++ 0x'de decltypeAFAIK aynı işi yapan bir şey var .

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

Halbuki typeidpolimorfik tiplerde kullanılır. Örneğin, şunu elde catedelim 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.
}

Teşekkürler Arak! Gönderiyi yeni sorularla güncelledim. Lütfen mümkünse bir göz atın.
Tim

4

typeid, istendiğinde çalışma zamanında verilerin türünü sağlar. Typedef, bundan sonra belirtildiği gibi yeni bir tür tanımlayan bir derleme zamanı yapısıdır. C ++ Çıktısında hiçbir tür yoktur (yazılı yorumlar olarak gösterilir):

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

Güzel görünen bir ad elde etmek için Boost demangle'ı kullanabilirsiniz:

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

ve benzeri bir şey

To_main_msg_evt ev("Failed to initialize cards in " + boost::units::detail::demangle(typeid(*_IO_card.get()).name()) + ".\n", true, this);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.