2008-12-09 47 views
115

Tôi có lớp A và một lớp khác kế thừa từ đó, B. Tôi ghi đè hàm đang chấp nhận đối tượng kiểu A làm tham số, vì vậy tôi phải chấp nhận A. Tuy nhiên, sau đó tôi gọi các chức năng mà chỉ B có, vì vậy tôi muốn trả về false và không tiến hành nếu đối tượng được truyền không thuộc loại B.Tìm loại đối tượng trong C++

Cách tốt nhất để tìm ra loại đối tượng được truyền cho hàm của tôi là gì Là?

Trả lời

134

dynamic_cast nên làm các trick

TYPE& dynamic_cast<TYPE&> (object); 
TYPE* dynamic_cast<TYPE*> (object); 

Từ khóa dynamic_cast phôi một dữ liệu từ một con trỏ hoặc tham chiếu loại khác, thực hiện một kiểm tra thời gian chạy để đảm bảo tính hợp lệ của các diễn viên.

Nếu bạn cố gắng truyền tới con trỏ tới loại không phải là loại đối tượng thực, kết quả của phép tính sẽ là NULL. Nếu bạn cố gắng truyền để tham chiếu đến loại không phải là loại đối tượng thực, dàn diễn viên sẽ ném một ngoại lệ bad_cast.

Đảm bảo có ít nhất một hàm ảo trong lớp cơ sở để thực hiện công việc dynamic_cast.

+0

Điều gì làm bạn có nghĩa là phải có một chức năng ảo trong lớp cơ sở để làm cho công việc dynamic_cast. Điều đó dường như với tôi quan trọng, rằng tôi sẽ đoán. – GiCo

+0

OK tìm thấy nó: Thông tin loại thời gian chạy (RTTI) chỉ có sẵn cho các lớp đa hình, có nghĩa là chúng có ít nhất một phương thức ảo. dynamic_cast và typeid cần RTTI. – GiCo

+0

Không 'dynamic_cast' ném nếu nó không chuyển đổi? Có cách nào để làm điều đó mà không tạo ra một cú ném? – jww

19

Điều này được gọi là RTTI, nhưng bạn gần như chắc chắn muốn xem xét lại thiết kế của bạn ở đây, vì việc tìm kiếm loại và thực hiện những điều đặc biệt dựa trên nó làm cho mã của bạn trở nên giòn hơn.

+3

True. Thật không may tôi đang làm việc trên một dự án hiện tại vì vậy tôi không thể thực sự thay đổi thiết kế, hoặc bất cứ điều gì trong lớp A. – lemnisca

6

Bạn đang tìm kiếm dynamic_cast<B*>(pointer)?

2

Mô tả của bạn hơi khó hiểu.

Nói chung, mặc dù một số triển khai C++ có cơ chế cho nó, bạn không phải hỏi về loại đó. Thay vào đó, bạn có nghĩa vụ phải làm một dynamic_cast trên con trỏ đến A. Điều này sẽ làm là lúc chạy, nội dung thực tế của con trỏ đến A sẽ được kiểm tra. Nếu bạn có một B, bạn sẽ nhận được con trỏ của bạn để B. Nếu không, bạn sẽ nhận được một ngoại lệ hoặc null.

+1

Cần lưu ý bạn sẽ nhận được một ngoại lệ * chỉ * nếu bạn thực hiện một diễn viên tham khảo mà không thành công. tức là dynamic_cast (t). Thất bại con trỏ phôi trả về NULL. tức là dynamic_cast (t) – AlfaZulu

+0

Phải, tôi nên làm rõ điều đó tốt hơn. Cảm ơn. Tôi muốn có một từ mô tả trong các loại C có tham chiếu thay vì theo giá trị. – Uri

8

lẽ nhúng vào đối tượng của bạn một ID "tag" và sử dụng nó để phân biệt giữa các đối tượng của lớp A và đối tượng của lớp B.

Tuy nhiên điều này cho thấy một lỗ hổng trong thiết kế. Lý tưởng nhất là những phương pháp trong B mà A không có, nên là một phần của A nhưng để trống, và B ghi đè chúng. Điều này không phù hợp với mã lớp cụ thể và có nhiều hơn trong tinh thần của OOP.

2

Vì những người khác cho biết bạn có thể sử dụng dynamic_cast. Nhưng nói chung bằng cách sử dụng dynamic_cast để tìm ra loại của lớp dẫn xuất bạn đang làm việc khi chỉ ra thiết kế xấu. Nếu bạn đang ghi đè một hàm lấy con trỏ của A làm tham số thì nó sẽ có thể làm việc với các phương thức/dữ liệu của lớp A và không nên phụ thuộc vào dữ liệu của lớp B. Trong trường hợp của bạn thay vì ghi đè nếu bạn chắc chắn rằng phương pháp bạn đang viết sẽ chỉ hoạt động với lớp B, sau đó bạn nên viết một phương thức mới trong lớp B.

0

Sử dụng các chức năng quá tải. Không yêu cầu dynamic_cast hoặc thậm chí hỗ trợ RTTI:

class A {}; 
class B : public A {}; 

class Foo { 
public: 
    void Bar(A& a) { 
     // do something 
    } 
    void Bar(B& b) { 
     Bar(static_cast<A&>(b)); 
     // do B specific stuff 
    } 
}; 
+0

Ngay từ câu hỏi ban đầu: "Sau này tôi gọi các hàm chỉ B có" - cách quá tải sẽ hoạt động trong trường hợp như vậy? –

+0

Khi bạn gọi cho Bar với nội dung A, không có gì xảy ra. Khi bạn gọi Bar với B, các phương thức chỉ tồn tại trên B có thể được gọi. Bạn có đọc câu hỏi gốc không? Bar là của anh ta "Tôi đang ghi đè một chức năng chấp nhận một đối tượng của loại A như một tham số" – jmucchiello

+6

Điều này không làm việc với đa hình năng động, mà tôi nghi ngờ người hỏi đang sử dụng. C++ không thể chọn quá tải dựa trên lớp thời gian chạy của tham số, chỉ dựa trên kiểu thời gian biên dịch. –

113

động dàn diễn viên là tốt nhất cho mô tả của bạn về vấn đề, nhưng tôi chỉ muốn thêm mà bạn có thể tìm thấy những kiểu lớp với:

#include <typeinfo> 

... 
string s = typeid(YourClass).name() 
+3

Tốt nếu bạn thực sự không biết đối tượng của bạn là gì. Câu trả lời được chấp nhận giả định bạn làm. – unludo

+1

là loại thông tin tiêu chuẩn? – xus

+4

@xus Có. nó là một phần của tiêu đề std –

2

Bởi vì lớp của bạn không đa hình.Thử:

struct BaseClas { int base; virtual ~BaseClas(){} }; 
class Derived1 : public BaseClas { int derived1; }; 

Hiện tại BaseClas là đa hình. Tôi đã thay đổi class thành struct bởi vì các thành viên của một struct là public theo mặc định.

3

Chỉ cần được hoàn thành, tôi sẽ xây dựng xây dựng tắt của Robocide và chỉ ra rằng typeid có thể được sử dụng một mình mà không sử dụng name():

#include <typeinfo> 
#include <iostream> 

using namespace std; 

class A { 
public: 
    virtual ~A() = default; // We're not polymorphic unless we 
          // have a virtual function. 
}; 
class B : public A { } ; 
class C : public A { } ; 

int 
main(int argc, char* argv[]) 
{ 
    B b; 
    A& a = b; 

    cout << "a is B: " << boolalpha << (typeid(a) == typeid(B)) << endl; 
    cout << "a is C: " << boolalpha << (typeid(a) == typeid(C)) << endl; 
    cout << "b is B: " << boolalpha << (typeid(b) == typeid(B)) << endl; 
    cout << "b is A: " << boolalpha << (typeid(b) == typeid(A)) << endl; 
    cout << "b is C: " << boolalpha << (typeid(b) == typeid(C)) << endl; 
} 

Output:

a is B: true 
a is C: false 
b is B: true 
b is A: false 
b is C: false 
+0

Ví dụ hay. Cảm ơn! – user

0

Nếu bạn có thể truy cập thư viện tăng cường, có thể type_id_with_cvr() chức năng là những gì bạn cần, có thể provide data type without removing const, volatile, & and && modifiers. Dưới đây là một ví dụ đơn giản trong C++ 11:

#include <iostream> 
#include <boost/type_index.hpp> 

int a; 
int& ff() 
{ 
    return a; 
} 

int main() { 
    ff() = 10; 
    using boost::typeindex::type_id_with_cvr; 
    std::cout << type_id_with_cvr<int&>().pretty_name() << std::endl; 
    std::cout << type_id_with_cvr<decltype(ff())>().pretty_name() << std::endl; 
    std::cout << typeid(ff()).name() << std::endl; 
} 

Hy vọng điều này hữu ích.

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