2012-06-17 24 views
13

Tôi đã tìm thấy một giải pháp đơn giản ở đâu đó trên internet với một lớp nhận dạng mà không được tích hợp sẵn trong C++ RTTI.Danh tính lớp không có RTTI

template <typename T> 
class Identity { 
public: 
    static int64_t id() 
    { 
     static int64_t dummy; 
     return reinterpret_cast<int64_t>(&dummy); 
    } 
}; 

Khi chúng ta cần một số lớp ID, chúng ta chỉ cần sử dụng:

Identity<OurClass>::id(); 

Tôi đang tự hỏi, là có bất kỳ va chạm? Nó có thể trả lại cùng một ID cho các lớp khác nhau hoặc ID khác nhau cho cùng một lớp không? Tôi đã thử mã này với g ++ với các giá trị tối ưu hóa khác nhau, mọi thứ có vẻ ok.

+0

Về nguyên tắc, có. Không có gì đảm bảo rằng con trỏ hàm có cùng kích thước với 'int'. –

+1

Điều này có liên quan đến sở thích của tôi ... –

+0

Để tránh vấn đề trên, tốt hơn nên đặt biến 'int' tĩnh trong mẫu hàm thành viên tĩnh đó và trả về một con trỏ tới * đó *. Trình biên dịch sẽ tối ưu hóa các chức năng đi anyway. – Electro

Trả lời

12

Trước hết: có một loại không thể thiếu như vậy được thực hiện cụ thể để chứa con trỏ:

  • intptr_t
  • và trong C++ 11 uintptr_t

Thứ hai, mặc dù trong thực tế trên gcc chúng bằng nhau, kích thước của một con trỏ tới một đối tượng và kích thước của một con trỏ hàm (hoặc con trỏ đến thành viên) có thể khác nhau. Vì vậy nó sẽ tốt hơn bằng cách sử dụng một đối tượng cụ thể chứ không phải là chính phương thức đó (cho sự phù hợp tiêu chuẩn). Thứ ba, nó chỉ cung cấp cho bạn danh tính, trong khi RTTI phong phú hơn nhiều, vì nó biết về tất cả các lớp con của một đối tượng nhất định có thể được đúc, và thậm chí cho phép cross-phôi hoặc phôi trên thừa kế ảo.

Tuy nhiên, phiên bản hiệu chỉnh có thể hữu ích Tôi đoán:

struct Foo { 
    static intptr_t Id() { 
     static boost::none_t const Dummy = {}; 
     return reinterpret_cast<intptr_t>(&Dummy); 
    } 
}; 

Và trong hệ thống phân cấp, có một chức năng virtual trở ID đó.

Để hoàn thành, tôi sẽ đề cập rằng Clang và LLVM có cách riêng để xử lý đối tượng nhận dạng mà không có RTTI. Bạn có thể muốn đọc về cách triển khai isa, castdyn_casthere của chúng tôi.

+0

Được thăng hạng để được giải thích toàn diện. – Electro

+0

cảm ơn, nhưng tôi đã không nhận được, tại sao kích thước của một con trỏ đến một đối tượng và kích thước của một con trỏ hàm có thể khác nhau? bạn có thể đưa ra một ví dụ không? – pproger

+0

@pproger: Kích thước của con trỏ hàm thành viên ảo thường khác về kích thước từ con trỏ thông thường. Tuy nhiên đây là trình biên dịch cụ thể, bạn có thể đọc thêm về điều này trong bài viết mã hóa tuyệt vời này: http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible –

-1

Giải pháp này đưa con trỏ hàm vào một số int. Không đảm bảo rằng con trỏ này vừa với một số int, mặc dù trong thực tế sizeof(void *) == sizeof(void (*)()) <= sizeof(int)

Chỉnh sửa: Rất tiếc. Trên x86_64 sizeof(int) = 4, sizeof(void (*)()) = 8, do đó có thể xảy ra va chạm và không thể đoán trước được.

Bạn có thể truyền đến tích phân kích thước phù hợp, nhưng vẫn là hành vi không xác định theo lý thuyết.

+0

Điều đó không phải lúc nào cũng đúng trong thực tế; thử trên x86-64. –

+0

ok, tôi đã chỉnh sửa mã. những gì bây giờ? – pproger

0

phiên bản này tránh hành vi undefined (và cảnh báo trình biên dịch):

template <typename T> 
class Identity { 
public: 
    static const int* id() { static const int id = 0; return &id; } 
}; 
+0

tôi không cần giá trị trả về như con trỏ. Tôi muốn int :) – pproger

+0

Tại sao bạn quan tâm có hay không đó là một con trỏ? – Electro

+0

tôi không. tác giả của mã số) – pproger

Các vấn đề liên quan