'typeid' so với 'typeof' trong C ++


158

Tôi tự hỏi sự khác biệt giữa typeidtypeoftrong C ++. Đây là những gì tôi biết:

  • typeidđược đề cập trong tài liệu về type_info , được định nghĩa trong tập tin typeinfo C ++ .

  • typeofđược định nghĩa trong phần mở rộng GCC cho C và trong thư viện C ++ Boost .

Ngoài ra, đây là bài kiểm tra mã kiểm tra mà tôi đã tạo ở nơi tôi phát hiện ra typeidkhông trả lại những gì tôi mong đợi. Tại sao?

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

đầu ra:

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

8
Theo cách nào bạn nghĩ mã của bạn không in đúng tên loại? Nó có vẻ tốt với tôi. Chuỗi thực tế được trả về bởi name()được xác định thực hiện. Nó không phải là một tên định danh C ++ hợp lệ, chỉ là một cái gì đó xác định duy nhất loại. Có vẻ như việc triển khai của bạn sử dụng lược đồ xáo trộn tên chung của trình biên dịch.
Rob Kennedy

Cảm ơn Rob! Tôi đã mong đợi những tên giống hệt như tên loại như tôi đã thấy trong en.wikipedia.org/wiki/Typeid. Mangling tên có thể làm gì ở đây?
Tim

Nếu bạn chưa quen với kiểu chữ như tôi: Bạn cần một hàm ảo trong loại cơ sở để bật vtable hoặc dòng cuối cùng sẽ in loại cơ sở.
jw_

Câu trả lời:


198

Ngôn ngữ C ++ không có những thứ như typeof. Bạn phải xem xét một số phần mở rộng dành riêng cho trình biên dịch. Nếu bạn đang nói về GCC typeof, thì một tính năng tương tự có trong C ++ 11 thông qua từ khóa decltype. Một lần nữa, C ++ không có typeoftừ khóa như vậy .

typeidlà một toán tử ngôn ngữ C ++ trả về thông tin nhận dạng kiểu trong thời gian chạy. Về cơ bản, nó trả về một type_infođối tượng, có thể so sánh bằng với các type_infođối tượng khác .

Lưu ý rằng thuộc tính được xác định duy nhất của type_infođối tượng được trả về là thuộc tính tương đương và không bằng nhau, tức là type_infocác đối tượng mô tả các loại khác nhau sẽ so sánh không bằng nhau, trong khi type_infocác đối tượng mô tả cùng loại phải so sánh bằng nhau. Mọi thứ khác được thực hiện xác định. Các phương thức trả về các "tên" khác nhau không được đảm bảo để trả về mọi thứ mà con người có thể đọc được và thậm chí không được bảo đảm để trả lại bất cứ thứ gì.

Cũng lưu ý rằng, điều trên có lẽ ngụ ý (mặc dù tiêu chuẩn dường như không đề cập rõ ràng) rằng các ứng dụng liên tiếp typeidcùng loại có thể trả về các type_infođối tượng khác nhau (tất nhiên, vẫn phải so sánh bằng nhau).


1
Điều này có cần cập nhật vì C ++ 11 decltypekhông? Tôi không chắc chính sách chung là gì, nhưng khi câu hỏi được gắn thẻ, C++tôi hy vọng nó sẽ đề cập đến tiêu chuẩn mới nhất. Đọc lại câu hỏi C++03cũng sẽ là một tùy chọn imho. Cá nhân tôi đôi khi khá bối rối, vì tôi phải sử dụng preC ++ 11 tại nơi làm việc và đôi khi tôi không chắc đâu là "pre11" hay "post11".
idclev 463035818

11
FYI, decltypekhông phải là một thay thế cho typeof. typeofhoạt động trên các loại quá trong khi decltypekhông. Ví dụ, typeof(int)inttrong khi decltype(int)là một lỗi.
Shahbaz

1
"Các type_infođối tượng mô tả các loại khác nhau sẽ so sánh không bằng nhau" . Trên thực tế, điều này không được đảm bảo . Toán tử bất đẳng thức đã được loại bỏ trong C ++ 20 thành (tôi giả sử) không khuyến khích dựa vào các loại khác nhau so sánh không bằng nhau. Nhưng nếu bạn nghĩ về nó, bình đẳng sẽ không an toàn nếu bất bình đẳng không an toàn.
Indiana Kernick

50

Sự khác biệt chính giữa hai là sau

  • typeof là cấu trúc thời gian biên dịch và trả về kiểu như được định nghĩa tại thời gian biên dịch
  • typeid là một cấu trúc thời gian chạy và do đó cung cấp thông tin về loại thời gian chạy của giá trị.

loại tham khảo: http ://www.d Bachelorie.com/gnu/docs/gcc/gcc_36.html

tài liệu tham khảo: https://en.wikipedia.org/wiki/Typeid


Cảm ơn bạn, JaredPar! Tôi có một số câu hỏi mới trong bài cập nhật sau khi đọc câu trả lời của bạn. Chẳng hạn như nếu đúng thì lợi nhuận của chúng được sử dụng cho các mục đích khác nhau: lợi nhuận của typeof được sử dụng làm từ khóa loại có thể xác định biến, nhưng lợi nhuận của typeid có thể không?
Tim

26

typeidcó thể hoạt động trong thời gian chạy và trả về một đối tượng mô tả loại thời gian chạy của đối tượng, phải là một con trỏ tới một đối tượng của một lớp với các phương thức ảo để RTTI (thông tin loại thời gian chạy) được lưu trữ trong lớp. Nó cũng có thể đưa ra kiểu thời gian biên dịch của một biểu thức hoặc tên kiểu, nếu không được cung cấp một con trỏ tới một lớp có thông tin kiểu thời gian chạy.

typeoflà một phần mở rộng GNU và cung cấp cho bạn loại biểu thức bất kỳ tại thời gian biên dịch. Điều này có thể hữu ích, ví dụ, trong việc khai báo các biến tạm thời trong các macro có thể được sử dụng trên nhiều loại. Trong C ++, bạn thường sẽ sử dụng các mẫu thay thế.


5
Theo như tôi biết, typeidsẽ chấp nhận bất kỳ biểu thức nào, không chỉ những biểu thức đánh giá đối tượng bằng các phương thức ảo. Hơn nữa, typeidsẽ chấp nhận một tên loại , không chỉ là một biểu thức. Bạn có thể nói typeid(5)hoặc typeid(std::string)nếu bạn muốn.
Rob Kennedy

1
Tôi đã làm rõ câu trả lời của mình để làm rõ điều đó; typeid có thể trả về thông tin loại thời gian chạy nếu có, nhưng sẽ cung cấp thông tin loại thời gian biên dịch cho bất kỳ thứ gì khác.
Brian Campbell

Cảm ơn bạn, Brian và Rob! Tôi có một số câu hỏi mới trong bài cập nhật sau khi đọc câu trả lời của bạn.
Tim

22

Trả lời câu hỏi bổ sung:

mã kiểm tra sau đây của tôi cho typeid không xuất ra tên loại chính xác. chuyện gì vậy?

Không có gì sai cả. Những gì bạn thấy là đại diện chuỗi của tên loại. C ++ tiêu chuẩn không buộc các trình biên dịch phát ra tên chính xác của lớp, nó chỉ phụ thuộc vào người triển khai (nhà cung cấp trình biên dịch) để quyết định cái gì là phù hợp. Trong ngắn hạn, các tên là tùy thuộc vào trình biên dịch.


Đây là hai công cụ khác nhau. typeoftrả về kiểu của một biểu thức, nhưng nó không chuẩn. Trong C ++ 0x, có một cái gì đó được gọi là decltypeAFAIK.

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

Trong khi đó typeidđược sử dụng với các loại đa hình. Ví dụ: giả sử rằng catxuất phát 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.
}

Cảm ơn, Arak! Tôi chỉ cập nhật bài viết với một số câu hỏi mới. Xin hãy xem nếu có thể.
Tim

4

typeid cung cấp loại dữ liệu khi chạy, khi được yêu cầu. Typedef là một cấu trúc thời gian biên dịch xác định một loại mới như đã nêu sau đó. Không có kiểu chữ nào trong Đầu ra C ++ xuất hiện dưới dạng (hiển thị dưới dạng các chú thích được ghi):

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

Bạn có thể sử dụng Boost demangle để hoàn thành một cái tên đẹp mắt:

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

và một cái gì đó như

To_main_msg_evt ev("Failed to initialize cards in " + boost::units::detail::demangle(typeid(*_IO_card.get()).name()) + ".\n", true, this);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.