2010-11-03 43 views
14

Đã lâu rồi tôi phải viết mã C++ và tôi cảm thấy ngớ ngẩn. Tôi đã viết mã mà là tương tự, nhưng không phải là chính xác, mã bên dưới:Làm cách nào để truyền một lớp cha mẹ làm lớp con

class Parent 
{ 
    ... 
}; 

class Child : public Parent 
{ 
    ... 
}; 

class Factory 
{ 
    static Parent GetThing() { Child c; return c; } 
}; 

int main() 
{ 
    Parent p = Factory::GetThing(); 
    Child c1 = p; // Fails with "Cannot convert 'Parent' to 'Child'" 
    Child c2 = (Child)p; // Fails with "Could not find a match for 'TCardReadMessage::TCardReadMessage(TCageMessage)'" 
} 

Tôi biết điều này được coi là đơn giản nhưng tôi không chắc chắn những gì tôi đang làm sai.

+0

Tôi không hiểu nhà máy đang làm gì. Có vẻ như nó trả về biến cục bộ. Đối tượng đó có hợp lệ không? – John

+4

@John: nó trả về một bản sao của một đối tượng địa phương. Sự trở lại là giá trị, do đó, nó không quan trọng cho dù bản gốc chết sau đó (và tất nhiên, nó không). Không có gì sai với điều đó, khác hơn là nó không thích hợp cho một chức năng nhà máy ... –

+0

Vâng, phương thức GetThing trên lớp Factory sẽ trả về một biến cục bộ. Mà dường như sẽ không làm những gì tôi muốn. Tôi nên sử dụng con trỏ để thay thế. Ít nhất là theo các câu trả lời dưới đây. – Mykroft

Trả lời

15

A Parent đối tượng được trả về theo giá trị không thể có thể chứa bất kỳ thông tin Child nào. Bạn phải làm việc với con trỏ, tốt nhất là con trỏ thông minh, vì vậy bạn không cần phải dọn dẹp sau chính mình:

#include <memory> 

class Factory 
{ 
    // ... 

public: 

    static std::auto_ptr<Parent> GetThing() 
    { 
     return std::auto_ptr<Parent>(new Child()); 
    } 
}; 

int main() 
{ 
    std::auto_ptr<Parent> p = Factory::GetThing(); 
    if (Child* c = dynamic_cast<Child*>(p.get())) 
    { 
     // do Child specific stuff 
    } 
} 
+1

GetThing nên [trả về auto_ptr] (hoặc http://stackoverflow.com/q/1837665/54262) (hoặc tương tự). Sau đó, bạn có thể gán giá trị trả về trực tiếp vào một con trỏ thông minh hoặc sử dụng phương thức phát hành của auto_ptr. –

+0

GetThing() cần phải được công khai. – bjskishore123

+0

Thứ nhất, 'Child * c' trong biểu thức truyền. Bạn đã bỏ lỡ '*'. Thứ hai, một 'dynamic_cast' downcasting đòi hỏi một loại đa hình. Các loại OP không được biết là đa hình. Nếu 'Parent' không đa hình, mã của bạn sẽ không biên dịch. – AnT

1

Bạn không thể, thực sự. Nhà máy của bạn đã trả lại đối tượng Parent, được xây dựng từ đối tượng Childc [*]. Phần con của nó đã bị cắt đi, vì nó được trả về hàm main. Không có cách nào để phục hồi nó.

Có lẽ bạn muốn sử dụng con trỏ?

[*] Trừ trường hợp đó, Child c(); tuyên bố một hàm, nó không xác định đối tượng. Nhưng đây không phải là mã thực sự của bạn, và tôi đoán lớp thực sự của bạn có các tham số hàm tạo.

+0

Vâng xin lỗi đó là một giả định chính xác về các nhà xây dựng. – Mykroft

-1

Bạn không thể truyền các đối tượng thực sự, nhưng bạn có thể truyền con trỏ tới các đối tượng.

Để đúc đang gợi ý sử dụng như thế này:

Child* c = reinterpret_cast<Child*>(p); 
+2

Tôi khuyên bạn nên 'dynamic_cast' –

+0

Đồng ý với max - reinterpret_cast có thể được xem là" last resort cast ":) – Flexo

+0

Tại sao tôi sử dụng dynamic_cast hoặc reinterpret_cast thay vì chỉ nói' Child * c = (child *) p; ' – Mykroft

0

Bạn không thể cast một đối tượng của lớp cha để kiểu lớp trẻ. Một đối tượng của lớp cha là ... tốt, một đối tượng của lớp cha. Lớp con mở rộng lớp cha, có nghĩa là đối tượng của lớp cha thường nhỏ hơn một đối tượng của lớp con. Vì lý do này đúc (hoặc reinterpreting) lớp cha mẹ như lớp con không có ý nghĩa gì.

Giải thích bạn đang cố gắng làm gì. Nếu không có một lời giải thích, câu hỏi của bạn chỉ đơn giản là không có ý nghĩa.

2

Tôi nghĩ rằng vấn đề không phải là cách bạn cố gắng thực hiện dàn diễn viên, nhưng với lý do tại sao bạn muốn truyền đầu tiên. Mã không có ý nghĩa - ngay cả khi nó hợp lệ về mặt pháp lý. Bạn đang cố gắng để đúc một "trái cây" thành một "quả táo" trong một bối cảnh mà nó dễ dàng để chứng minh rằng bạn không thực sự có một quả táo. Dynamic phôi và tương tự chỉ hữu ích khi bạn có một con trỏ đến một "trái cây" mà bạn có lý do để điều cũng là một "quả táo".

+0

Mã này chỉ là một ví dụ để hiển thị các phần liên quan về cách mã của tôi được đặt cùng nhau. Nó không phải là mã sản xuất thực tế của tôi. – Mykroft

0

Có thể bạn không muốn truyền ở đây cả. Nếu Parent có bất kỳ phương thức trừu tượng nào bạn chỉ cần gọi chúng và lớp dẫn xuất sẽ tự động xử lý chúng một cách chính xác. Có những lúc bạn liên kết các mục tương đối không liên quan với nhau để bạn có thể lưu trữ chúng trong một bộ sưu tập, hoặc loại biến thể hoặc tình huống mà các trạng thái khác nhau dẫn đến các đối tượng không liên quan được xử lý khác nhau, và vào những dịp bạn có thể muốn truyền .

Tôi khá ngạc nhiên, bằng cách này, bạn đã không nhận được lỗi trình biên dịch trên GetThing() vì bạn đã khai báo c làm hàm để bạn không trả về một Phụ huynh.

Bên cạnh đó, bằng cách này, nếu bạn sao chép bởi giá trị mà bạn sẽ "lát" như sau:

Child c; 
Parent p(c); 
Child & c2 = dynamic_cast< Child& >(p); // throws bad_cast 
0

Tham khảo các đoạn mã dưới đây:

Child* c = dynamic_cast<Child*>(parentObject); 

nơi, parentObject là loại Parent*

Đảm bảo rằng "parentObject" thực sự thuộc loại "Trẻ em", nếu không hành vi không xác định.

Tham khảo More Info

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