2009-06-20 29 views
6

xem xét:C++: Có thể sao chép đa hình Constructors làm việc?

class A 
{ 
public: 
    A(int val) : m_ValA(val) {} 
    A(const A& rhs) {} 
    int m_ValA; 
}; 

class B : public A 
{ 
public: 
    B(int val4A, int val4B) : A(val4A), m_ValB(val4B) {} 
    B(const B& rhs) : A(rhs), m_ValB(rhs.m_ValB) {} 
    int m_ValB; 
}; 

int main() 
{ 
    A* b1 = new B(1, 2); 
    A* b2 = new A(*b1); // ERROR...but what if it could work? 
    return 0; 
} 

Would C++ bị phá vỡ nếu "mới A (b1)" đã có thể giải quyết để tạo ra một bản sao B mới và trở về A?

Điều này thậm chí có hữu ích không?

Trả lời

19

Bạn có cần chức năng này hay đây chỉ là một thử nghiệm suy nghĩ?

Nếu bạn cần phải làm điều này, các thành ngữ phổ biến là có một phương pháp Clone:

class A 
{ 
public: 
    A(int val) : m_ValA(val) {} 
    A(const A& rhs) {} 
    virtual A *Clone() = 0; 
    int m_ValA; 
}; 

class B : public A 
{ 
public: 
    B(int val4A, int val4B) : A(val4A), m_ValB(val4B) {} 
    B(const B& rhs) : A(rhs), m_ValB(rhs.m_ValB) {} 
    A *Clone() { return new B(*this); } 
    int m_ValB; 
}; 

int main() 
{ 
    A* b1 = new B(1, 2); 
    A* b2 = b1->Clone(); 
    return 0; 
} 
+5

+1, nhưng tôi cũng sẽ thêm một destructor ảo đến lớp;) –

+0

Quả thật là một thí nghiệm tưởng tượng. Và trong khi đây là cách tiêu chuẩn để thực hiện các nhà xây dựng bản sao ảo, tôi đã tò mò tại sao ngôn ngữ không cung cấp một cách chuẩn hóa để làm điều này. – 0xC0DEFACE

+0

Trả về biến thể tốt hơn: B * B :: Clone() –

0

Yes. Có một số cách để thực hiện nhân bản (ví dụ phương pháp nhân bản tiêu chuẩn nhiều hơn hoặc ít hơn, các biến thể được tham số hóa của các nhà máy đối tượng, có hoặc không có tiêm phụ thuộc cấu hình) mà không thay đổi ý nghĩa của các chương trình hiện có. nó không thể tạo ra các cá thể của các lớp cơ sở khi một lớp dẫn xuất được biết đến trong một đơn vị biên dịch.

Các nhà xây dựng và trình phá hủy đủ phức tạp để hiểu cho người mới bắt đầu. Tiêm thậm chí phức tạp hơn vào chúng sẽ là không khôn ngoan.

1

Khái niệm

new A(*b1) 

đã có một ý nghĩa, giả như bạn có quá tải thích hợp.

Nếu nó có ý nghĩa khác, bạn phải cung cấp một cách khác để có được ý nghĩa khác. Đây là loại vô nghĩa khi đã có cách để có được ý nghĩa bạn muốn:

new B(*b1) 

Và hãy đoán rõ ràng hơn để đọc.

+1

Nhưng ví dụ thứ hai giả sử bạn biết một ưu tiên rằng 'b1' thực ra là một' B'. – user470379

+0

@ user470379 - tuyệt đối; quan điểm của tôi không phải là 'mới B (* b1)' là câu trả lời, đó là 'mới A (* b1)' không thể là câu trả lời. –

4

Những gì bạn đang thực sự tìm kiếm được gọi là virtual copy constructor và những gì được đăng là cách tiêu chuẩn để thực hiện.

Ngoài ra còn có clever ways of doing it with templates. (tuyên bố từ chối trách nhiệm: tự quảng cáo)

+0

Cảm ơn bạn đã liên kết thứ hai, tôi thích khái niệm này. – tommyk

0

Như đã nêu ở trên có một số cách để thực hiện việc này.

Để trả lời câu hỏi của bạn nếu new A(*b1) trả lại phiên bản B mới thì điều này sẽ không hoạt động.

int main() 
{ 
    A* b1 = new B(1, 2); 
    A a(*b1); // What size would 'a' be if it was polymorphicly constructed? 
    return 0; 
} 
2

Chỉ cần một bổ sung nhỏ để câu trả lời bằng cách eduffy: Thay vì

class B : public A { 
    ... 
    A *Clone() { return new B(*this); } 
    ... 

};

bạn có thể khai báo nó như thế này:

class B : public A { 
    ... 
    B *Clone() { return new B(*this); } // note: returning B * 
    ... 

};

Nó vẫn được coi là một trọng giá trị của ảo A::Clone(); và là tốt hơn nếu gọi trực tiếp thông qua B *

+0

Tuyệt vời, nhưng tôi không hiểu tại sao nó hợp lệ? ^^ – Thecheeselover

+0

Vì đó là các kiểu trả về biến đổi. § 10.3.7 –

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