'typeid' กับ 'typeof' ใน C ++


159

ฉันสงสัยว่าอะไรคือความแตกต่างระหว่างtypeidและtypeofใน C ++ นี่คือสิ่งที่ฉันรู้:

  • typeidถูกกล่าวถึงในเอกสารสำหรับ type_infoซึ่งถูกกำหนดไว้ใน C ++ ไฟล์ส่วนหัวtypeinfo

  • typeofถูกกำหนดในส่วนขยาย GCC สำหรับ C และในไลบรารี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 ++ ที่ถูกต้องเพียงบางสิ่งที่ระบุประเภทเฉพาะ ดูเหมือนว่าการติดตั้งของคุณจะใช้รูปแบบการเขียนชื่อ mangling ทั่วไปของคอมไพเลอร์
Rob Kennedy

ขอบคุณ Rob! ฉันคาดหวังว่าชื่อเหล่านั้นจะเหมือนกับชื่อประเภทตามที่ฉันเห็นใน en.wikipedia.org/wiki/Typeid mangling ชื่อทำอะไรที่นี่?
ทิม

หากคุณยังใหม่กับ 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 ทำงานในประเภทเกินไปขณะที่ไม่ ยกตัวอย่างเช่นเป็นในขณะที่ยังเป็นข้อผิดพลาด typeoftypeofdecltypetypeof(int)intdecltype(int)
Shahbaz

1
"type_infoวัตถุอธิบายประเภทที่แตกต่างกันจะเปรียบที่ไม่เท่ากัน" จริงนี้ไม่สามารถรับประกันได้ ตัวดำเนินการความไม่เท่าเทียมกันถูกลบออกใน C ++ 20ถึง (ฉันถือว่า) หมดกำลังใจโดยอาศัยประเภทที่แตกต่างกันเมื่อเปรียบเทียบไม่เท่ากัน แต่ถ้าคุณคิดเกี่ยวกับมันความเท่าเทียมกันจะไม่ปลอดภัยหากความไม่เท่าเทียมนั้นไม่ปลอดภัย
Indiana Kernick

51

ความแตกต่างหลักระหว่างสองคือต่อไปนี้

  • typeof คือการสร้างเวลารวบรวมและส่งกลับชนิดตามที่กำหนดในเวลารวบรวม
  • typeid เป็นตัวสร้างรันไทม์ดังนั้นจึงให้ข้อมูลเกี่ยวกับประเภทรันไทม์ของค่า

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

การอ้างอิงประเภท: https://en.wikipedia.org/wiki/Typeid


ขอบคุณ JaredPar! ฉันมีคำถามใหม่ในโพสต์ที่ได้รับการปรับปรุงหลังจากอ่านคำตอบของคุณ เช่นถ้ามันเป็นความจริงที่ว่าผลตอบแทนของพวกเขาจะใช้เพื่อวัตถุประสงค์ที่แตกต่างกัน: การกลับมาของ typeof จะใช้เป็นคำหลักประเภทที่สามารถกำหนดตัวแปร แต่การกลับมาของ typeid ไม่สามารถ?
ทิม

26

typeidสามารถทำงานได้ที่ runtime และคืนค่าวัตถุที่อธิบายชนิดเวลาทำงานของวัตถุซึ่งจะต้องเป็นตัวชี้ไปยังวัตถุของคลาสที่มีวิธีการเสมือนเพื่อให้RTTI (ข้อมูลชนิดรันไทม์)ถูกเก็บไว้ในคลาส นอกจากนี้ยังสามารถให้ประเภทเวลารวบรวมของการแสดงออกหรือชื่อประเภทถ้าไม่ได้รับตัวชี้ไปยังชั้นเรียนที่มีข้อมูลประเภทเวลาทำงาน

typeofเป็นส่วนขยายของ GNU และให้ประเภทของการแสดงออกใด ๆ ในเวลารวบรวม สิ่งนี้มีประโยชน์เช่นในการประกาศตัวแปรชั่วคราวในมาโครที่อาจใช้กับหลายประเภท ใน C ++ คุณมักจะใช้เทมเพลตแทน


5
เท่าที่ฉันรู้typeidจะยอมรับการแสดงออกใด ๆ ไม่เพียง แต่ผู้ที่ประเมินให้กับวัตถุด้วยวิธีการเสมือน นอกจากนี้typeidจะยอมรับชื่อประเภทไม่ใช่เฉพาะนิพจน์ คุณสามารถพูดtypeid(5)หรือtypeid(std::string)ถ้าคุณต้องการ
Rob Kennedy

1
ฉันชี้แจงคำตอบของฉันให้ชัดเจน typeid สามารถส่งคืนข้อมูลชนิดรันไทม์หากมี แต่จะให้ข้อมูลประเภทเวลาคอมไพล์สำหรับสิ่งอื่น
Brian Campbell

ขอบคุณไบรอันและร็อบ! ฉันมีคำถามใหม่ในโพสต์ที่ได้รับการปรับปรุงหลังจากอ่านคำตอบของคุณ
ทิม

22

ตอบคำถามเพิ่มเติม:

รหัสทดสอบต่อไปนี้สำหรับ typeid ของฉันไม่ได้พิมพ์ชื่อประเภทที่ถูกต้อง เกิดอะไรขึ้น

ไม่มีอะไรผิดปกติ สิ่งที่คุณเห็นคือการเป็นตัวแทนสตริงของชื่อประเภท C ++ มาตรฐานไม่ได้บังคับให้คอมไพเลอร์เปล่งชื่อที่แน่นอนของคลาส แต่มันก็ขึ้นอยู่กับผู้พัฒนา (ผู้ขายคอมไพเลอร์) เพื่อตัดสินใจว่าอะไรที่เหมาะสม ในระยะสั้นชื่อขึ้นอยู่กับคอมไพเลอร์


นี่เป็นเครื่องมือสองแบบที่แตกต่างกัน typeofส่งคืนชนิดของนิพจน์ แต่ไม่ใช่มาตรฐาน ใน C ++ 0x มีบางสิ่งที่เรียกว่าdecltypeซึ่งทำงาน AFAIK เดียวกัน

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

แต่ทว่า typeidใช้กับประเภท polymorphic ตัวอย่างเช่นสมมติว่า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 เป็นโครงสร้างเวลารวบรวมที่กำหนดประเภทใหม่ตามที่ระบุไว้หลังจากนั้น ไม่มี typeof ในการแสดงผล 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 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);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.