2008-10-28 18 views
5

Giả sử tôi có một lớp học Cơ sở và một số lớp Có nguồn gốc. Có cách nào để truyền một đối tượng đến một trong các lớp dẫn xuất mà không cần phải viết một cái gì đó như thế này:C++ đúc theo lập trình: có thể thực hiện được không?


string typename = typeid(*object).name(); 
if(typename == "Derived1") { 
    Derived1 *d1 = static_cast< Derived1*>(object); 
} 
else if(typename == "Derived2") { 
    Derived2 *d2 = static_cast < Derived2*>(object); 
} 
... 
else { 
    ... 
} 

Trả lời

22

Không.

Đọc trên đa hình. Hầu như mọi tình huống "diễn viên năng động" là một ví dụ về tính đa hình đang phải vật lộn để được thực hiện.

Bất kỳ quyết định nào bạn thực hiện trong dàn diễn viên năng động đã được thực hiện. Chỉ cần ủy nhiệm công việc thực sự cho các lớp con.

Bạn đã để lại phần quan trọng nhất trong ví dụ của mình. Công việc hữu ích, đa hình.

string typename = typeid(*object).name(); 
if(typename == "Derived1") { 
    Derived1 *d1 = static_cast< Derived1*>(object); 
    d1->doSomethingUseful(); 
} 
else if(typename == "Derived2") { 
    Derived2 *d2 = static_cast < Derived2*>(object); 
    d2->doSomethingUseful(); 
} 
... 
else { 
    ... 
} 

Nếu mọi phân lớp thực hiện doSomethingSử dụng, điều này đơn giản hơn rất nhiều. Và đa hình.

object->doSomethingUseful(); 
+0

Đây là chi tiết một phút nhưng tôi muốn đề cập đến. Bạn có nghĩa là d1-> và d2-> chứ không phải là d1. và d2. ,đúng? Vì các kiểu con trỏ sử dụng toán tử arrow để tiếp cận các hàm thành viên. :) –

3

Thông thường, đây là dấu hiệu của thiết kế kém. Tại sao bạn cần phải làm điều này? Nó có thể được thiết kế lại để điều này là không cần thiết.

1

Ví dụ của bạn sẽ không cổng vì định dạng chính xác của tên() không được chỉ định. Bạn có thể thử kết quả là dynamic_cast s. Dynamic_cast trả về một con trỏ rỗng nếu bạn truyền đến loại sai. Tuy nhiên, nếu bạn đang làm một kiểu như thế này, có gì đó sai với thiết kế của bạn.

9

Bạn có thể sử dụng dynamic_cast và kiểm tra NULL, nhưng tôi muốn mạnh mẽ xem xét việc tái cấu trúc mã thay thế.

Nếu bạn cần xử lý theo lớp con cụ thể, Template Method có thể hữu ích, nhưng không biết bạn đang cố gắng đạt được điều gì, đó chỉ là một dự đoán mơ hồ.

2

Bạn đang cố gắng hoàn thành, chính xác là gì? Theo kinh nghiệm của tôi, những thứ như thế này là dấu hiệu của thiết kế xấu. Đánh giá lại phân cấp lớp của bạn, bởi vì mục tiêu của thiết kế hướng đối tượng là làm cho những thứ như thế này không cần thiết.

5
Derived1* d1 = dynamic_cast< Derived1* >(object); 
if (d1 == NULL) 
{ 
    Derived2* d2 = dynamic_cast< Derived2* >(object); 
    //etc 
} 

tôi có các phương pháp sau vào loại smartpointer tôi, mô phỏng C# 'là' và 'như':

template< class Y > bool is() const throw() 
    {return !null() && dynamic_cast< Y* >(ptr) != NULL;} 
template< class Y > Y* as() const throw() 
    {return null() ? NULL : dynamic_cast< Y* >(ptr);} 
4

Bạn có thể làm điều này bằng dynamic_cast, ví dụ:

if (Derived1* d1 = dynamic_cast<Derived1*>(object)) { 
    // object points to a Derived1 
    d1->foo(); 
} 
else if (Derived2* d2 = dynamic_cast<Derived2*>(object)) { 
    // object points to a Derived2 
    d2->bar(); 
} 
else { 
    // etc. 
} 

Nhưng như những người khác đã nói, mã như thế này có thể chỉ ra một thiết kế xấu, và bạn thường nên sử dụng virtual functions để thực hiện hành vi đa hình.

1

Tôi nghĩ dynamic_cast là con đường để đi, nhưng tôi không nghĩ đây là thiết kế tồi cho tất cả các điều kiện có thể. Giả sử đối tượng được tạo bởi một trình cắm thêm mà tác giả ứng dụng không biết. Và trình cắm thêm cụ thể đó có thể tạo đối tượng kiểu Derived1 (là phiên bản cũ) hoặc đối tượng kiểu Derived2 (là phiên bản mới).Có lẽ giao diện plug-in không được thiết kế để làm công cụ phiên bản cụ thể, nó chỉ tạo đối tượng để ứng dụng phải thực hiện loại kiểm tra này để đảm bảo việc truyền/thực thi phù hợp. Sau đó, chúng ta có thể gọi một cách an toàn object.doSomethingUsefulThatDoesNotExistInDerived1();

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