2010-03-01 31 views
6

Làm cách nào để kiểm tra thời gian chạy nếu đối tượng thuộc loại ClassA hoặc loại ClassB có nguồn gốc? Trong một trường hợp, tôi phải xử lý cả hai trường hợp riêng lẻKiểm tra loại có nguồn gốc (C++)

ClassA* SomeClass::doSomething (ClassA*) 
{ 
    if(/* parameter is of type base class */) { 

    } else if { /* derived class */) { 

    } 
} 

Có thể tôi có thể nói rằng lớp dẫn xuất ClassB có một số khả năng đặc biệt. Nhưng làm cách nào để làm điều đó mà không thay đổi ClassA hiện tại?

+2

ClassA không cần biết bất kỳ điều gì về ClassB. –

+0

Kiểm tra các loại lớp, nói chung, là chỉ báo về thiết kế kém. Xem mô hình thiết kế * Visitor * để thay thế. Ngoài ra nghiên cứu về đa hình. –

Trả lời

20

Nói chung, một ý tưởng rất tồi tệ khi bật loại chính xác như vậy. Bằng cách này, bạn đang kết nối chặt chẽ phương pháp của bạn với các lớp dẫn xuất của ClassA. Bạn nên sử dụng đa hình. Giới thiệu phương thức virtual trong lớp A, ghi đè lên lớp B và chỉ cần gọi nó theo phương pháp của bạn.

Ngay cả khi tôi đã buộc phải xử lý các chức năng trong các chức năng bên ngoài bản thân đối với một số lý do, tôi sẽ làm một cái gì đó như:

class ClassA { 
    public: virtual bool hasSpecificFunctionality() { return false; } 
}; 

class ClassB : public ClassA { 
    public: virtual bool hasSpecificFunctionality() { return true; } 
}; 

ClassA* SomeClass::doSomething (ClassA* arg) 
{ 
    if (arg->hasSpecificFunctionality()) { 

    } else { 

    } 
} 
+0

+1 - nhưng anh ta nói rằng anh ta không muốn/không thể thay đổi ClassA, do đó, một chức năng ảo là ra khỏi câu hỏi. –

+2

@Poita_: Nếu bạn không thể thay đổi lớp cơ sở, có thể bạn nên đi với bố cục thay vì thừa kế ngay từ đầu. –

+0

Nếu anh ta cần sự đa hình từ lớp cơ sở ... thì sao? –

4

Tại sao không có phương thức doSomething() trên ClassB xử lý các khả năng bổ sung của ClassB? Đây là bản chất của đa hình.

+2

Không, đa hình đòi hỏi bạn phải có phương thức 'doSomething' trên' ClassA' (có thể là một dấu nháy), ghi đè nó trong 'LớpB'. Ví dụ này thậm chí còn cho thấy lý do: bạn không thể gọi 'ClassB :: doSomething()' trên một 'ClassA *'. – MSalters

2

slighlty khác nhau mà những gì bạn yêu cầu

ClassB* b; 
if ((b = dynamic_cast<ClassB*>(ptr)) == 0) { 
    // not a classB* 
} else { 
    // a classB* in b 
} 
3

Cú pháp là:

ClassA* SomeClass::doSomething (ClassA* pa) 
{ 
    ClassB* pb = dynamic_cast<ClassB*>(pa); 
    if(pb) ... 

(Lưu ý rằng đây chỉ hoạt động trong phạm vi phân cấp lớp đa hình Đó là, có phải chức năng ảo. liên quan.)

Tuy nhiên, bạn nên cố gắng tránh điều đó. Những gì bạn cần nó cho rằng không thể được giải quyết bằng cách áp dụng các chức năng ảo?

12

Sử dụng một dynamic_cast như sau:

ClassA* SomeClass::doSomething(ClassA *a) 
{ 
    if (dynamic_cast<DerivedClass *>(a)) { 
     .... 
    } else if (dynamic_cast<BaseClass *>(a)) { 
     .... 
    } 
} 

dynamic_cast<T *>(ptr) sẽ trả lại 0 trong trường hợp ptr không phải là con trỏ của loại T và sẽ trả lại con trỏ thuộc loại T nếu không.

dynamic_cast thường có thể tránh được và là chỉ báo về thiết kế/mã lỗi. Nếu bạn có thể tránh nó, hãy thử làm như vậy, vì nó yêu cầu RTTI trong lần thực thi cuối cùng của bạn.

+4

Nhưng hãy nhớ rằng đối số đó với dynamic_cast phải là một con trỏ (hoặc tham chiếu) đến một lớp đa hình (tức là lớp có ít nhất một phương thức ảo). Nếu không dynamic_cast sẽ thất bại. –

+2

Bạn sẽ cần phải thử cast thành 'DerivedClass' trước khi cast thành' BaseClass', vì 'BaseClass' cast sẽ thành công cho cả hai kiểu. –

+0

Điểm tốt :) Tôi đã chỉnh sửa câu trả lời. –

2

Những người khác đã chỉ ra rằng việc bật các loại thường là một ý tưởng tồi, vì vậy tôi sẽ không làm như vậy. Nếu bạn thực sự phải làm điều đó, bạn có thể sử dụng toán tử typeid chuyển vào loại năng động của một đối tượng:

ClassA* SomeClass::doSomething (ClassA* a) 
{ 
    if (typeid(*a) == typeid(ClassA)) { 
     /* parameter is of type base class */ 
    } else if (typeid(*a) == typeid(ClassB)) { 
     /* a specific derived class */ 
    } else { 
     /* some other derived class */ 
    } 
} 

dynamic_cast là tương tự, nhưng các xét nghiệm cho chuyển đổi, không bình đẳng:

ClassA* SomeClass::doSomething (ClassA* a) 
{ 
    if (ClassB *b = dynamic_cast<classB*>(a)) { 
     /* parameter is, or is derived from, ClassB */ 
    } else { 
     /* parameter is, or is derived from, ClassA but not ClassB */ 
    } 
} 

Những chỉ hoạt động nếu ClassA là đa hình (có nghĩa là, nó có ít nhất một chức năng ảo).

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