2014-10-12 16 views
7

Tôi muốn biết những gì hiện đại C++ 11 tương đương với instanceof của Java. Tôi đã thấy điều này SO post nhưng nó là khá cũ và đã tự hỏi nếu có một giải pháp tốt hơn, hiện đại hơn trong C + + 11?Tương đương với C++ 11 của ví dụ Java là gì

Tôi đã hy vọng có khả năng sử dụng công tắc chuyển đổi mà không phải sử dụng lớp học enum thủ công.

class A { 

}; 

class B : public A { 

} 

class C : public A { 

} 

on_event(A& obj) 
{ 
    switch (obj) { 
     case A: 
     case B: 
     case C: 
    } 
} 

Lớp cơ sở của tôi không có bất kỳ phương pháp hoặc chức năng ảo nào. Tôi đại diện cho một cây biểu hiện cho một trình phân tích cú pháp và lớp cơ sở chỉ là một trình giữ hình đa hình - giống như một ADT trong Haskell/OCaml.

+3

Bạn có yêu cầu 'dynamic_cast <>' không? Đó không phải là C++ 11 cụ thể. –

+0

Không có gì thay đổi: không có sự phản ánh trong tiêu chuẩn C++. Nếu bạn muốn bật thông tin loại thời gian chạy, bạn 'dynamic_cast' – quantdev

+0

Có thể quan tâm: http://stackoverflow.com/q/25495733/596781 –

Trả lời

12

Câu trả lời tương tự vẫn được áp dụng, và luôn luôn là như thế này trong C++:

if (C * p = dynamic_cast<C *>(&obj)) 
{ 
    // The type of obj is or is derived from C 
} 
else 
{ 
    // obj is not a C 
} 

xây dựng này đòi hỏi A là đa hình, ví dụ: có chức năng thành viên ảo. Cũng lưu ý rằng hành vi này khác với việc so sánh typeid(obj) == typeid(C), vì các kiểm tra sau cho nhận dạng loại chính xác, trong khi diễn viên động, cũng như số instanceof của Java, chỉ kiểm tra loại mục tiêu là lớp cơ sở của loại đối tượng có nguồn gốc cao nhất.

+1

nó cũng đòi hỏi 'RTTI', đó là một nỗi đau cho một số người dùng C++. – user2485710

+1

@ user2485710: Tôi không nghĩ rằng câu lệnh đó có ý nghĩa trong ngữ cảnh của * ngôn ngữ * C++. Mã này là hợp lệ C++, không có trình độ chuyên môn. –

+1

nếu bạn không có 'RTTI' điều đó sẽ không hoạt động, không quan trọng những gì bạn đang xem xét, nó chỉ cần thiết để cho rằng đoạn mã hoạt động đúng. – user2485710

-1

Nếu bạn sẵn sàng giới hạn bản thân với các loại được biết tại thời gian biên dịch (thay vì làm việc thông qua các con trỏ trên các lớp có vtables) - thì C++ 11 trở lên tương đương instanceof: Đây là std::is_base_of.

Bạn cũng có thể muốn xem std::is_convertiblestd::is_same.

+3

Tôi không chắc chắn làm thế nào mà giúp anh ta trừ khi ông làm cho nó một mẫu chức năng và biết các loại tại thời gian biên dịch. Tôi nghĩ rõ ràng là anh ấy đang nói về đa hình thời gian chạy – PeterT

+0

@PeterT: Hoàn toàn không đồng ý. Đó là, trong C++, đặc biệt là C++ hiện đại, chúng tôi làm rất nhiều với các loại biên dịch-thời gian, vì vậy đây là một câu trả lời hoàn toàn hợp lệ (ngay cả khi nó cần được chỉnh sửa). – einpoklum

0

Trong C++ dữ liệu cũ thuần túy (POD) không có thông tin loại thời gian chạy. Các lớp được mô tả tất cả lấy chính xác 1 byte và có các biểu diễn thời gian chạy giống hệt nhau trong bất kỳ trình biên dịch nào với tối ưu hóa lớp cơ sở trống.

Như những gì bạn muốn không thể thực hiện được.

Thêm trình phá hủy ảo vào lớp cơ sở bổ sung trong RTTI và hỗ trợ dynamic_cast.

Thêm trường enum hoặc int vào cơ sở được khởi tạo khác nhau cho mỗi lớp dẫn xuất cũng hoạt động.

Tuy nhiên, tùy chọn khác là để tạo một hàm mẫu, và lưu trữ một con trỏ đến nó, như vậy:

using my_type_id=void(*)(); 
template<class>void get_my_type_id_helper(){}; 
template<class T> my_type_id get_my_type_id(){return get_my_type_id_helper<T>;} 

và sau đó lưu trữ một my_type_id trong A khởi tạo một cách thích hợp. Điều này là tái phát minh RTTI, và khi bạn muốn nhiều tính năng hơn, bạn sẽ tiếp cận C++ RTTI overhead.

Trong C++ bạn chỉ trả tiền cho những gì bạn yêu cầu: bạn có thể yêu cầu các lớp học không có RTTI, bạn đã làm và nhận được nó.

RTTI là thông tin loại thời gian chạy. POD là dữ liệu cũ thuần túy, một thuật ngữ C++ 03. Nhiều lớp không phải là POD: cách dễ dàng là thêm một destructor virtual. C++ 11 có bố cục chuẩn và các thuật ngữ tổng hợp tốt hơn.

RTTI và POD về mặt kỹ thuật không đối lập nhau: có các lớp không có RTTI không phải là POD.Lưu ý rằng MSVC có các tùy chọn để không tạo RTTI và gấp Comdat tích cực của nó có thể phá vỡ RTTI thủ công tôi đã làm ở trên, trong cả hai trường hợp vi phạm tiêu chuẩn.

-1

Đừng làm vậy. Trong hầu hết các trường hợp, bạn nên xem xét thiết kế của mình khi bạn yêu cầu instanceof hoặc dynamic_cast.

Tại sao? Bạn có nhiều khả năng vi phạm Liskov's substitiontin principle.

Làm thế nào về phương pháp này:

class A { 
    public: 
    virtual void action(); 
    virtual ~A(); 
}; 

class B : public A { 
    public: void action() override; 
}; 

class C : public A { 
    public: void action() override; 
}; 

void on_event(A& obj) 
{ 
    obj.action(); 
} 

Lưu ý rằng khi @Yakk chỉ ra bạn cần ít nhất một virtual phương pháp nào để có được đa hình động. Và có một quy tắc cho biết: Khi bạn có ít nhất một phương thức ảo, luôn luôn viết một destructor ảo trong lớp cơ sở.

Bạn có thể làm tất cả điều này với các mẫu và chuyên môn hóa hoặc gắn thẻ loại nhưng tôi lấy từ câu hỏi của bạn - đến từ Java - bạn không muốn đến đó. Bạn thực sự như các phương pháp ảo, phải không? Xin lỗi, bạn phải đánh dấu chúng trong C++.

+0

Tôi không nghĩ rằng một chương trình bao gồm 3 lớp (A, B, C) vi phạm LSP và có thể được coi là một thiết kế tốt. Tôi muốn downvote gây ra một phần LSP là gây hiểu lầm (câu hỏi là về thay thế trực tiếp cho instanceof cho C++ 11 và cảnh báo của bạn đã được đề cập trong liên kết), nhưng ai đó có thể thấy nó hữu ích. – m039

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