"virtual constructor idiom" là trường hợp quan trọng khi cần có trình tạo bản sao riêng tư hoặc được bảo vệ. Một vấn đề nảy sinh trong C++, nơi bạn được đưa con trỏ tới một lớp cơ sở, của một đối tượng thực sự được kế thừa từ lớp cơ sở này và bạn muốn tạo một bản sao của nó. Việc gọi hàm tạo bản sao sẽ không gọi hàm tạo bản sao của lớp kế thừa, nhưng thực sự gọi hàm tạo bản sao của lớp cơ sở.
Quan sát:
class Base {
public:
Base(const Base & ref){ std::cout << "Base copy constructor" ; }
};
class Derived : public Base {
public:
Derived(const Derived & ref) : Base(ref) { std::cout << "Derived copy constructor"; }
}
Base * obj = new Derived;
Base * obj2 = new Derived(*obj);
Đoạn mã trên sẽ tạo ra kết quả:
"Base copy constructor"
Đây rõ ràng không phải là hành vi lập trình viên muốn! Các lập trình viên đã cố gắng để sao chép một đối tượng thuộc loại "Có nguồn gốc" nhưng thay vào đó đã trở lại một đối tượng của loại "Base" !!
Sự cố được khắc phục bằng cách sử dụng thành ngữ đã nói ở trên. Quan sát các ví dụ viết ở trên, lại ghi vào sử dụng thành ngữ này:
class Base {
public:
virtual Base * clone() const = 0; //this will need to be implemented by derived class
protected:
Base(const Base & ref){ std::cout << "Base copy constructor" ; }
};
class Derived : public Base {
public:
virtual Base * clone() const {
//call private copy constructor of class "Derived"
return static_cast<Base *>(new Derived(*this));
}
//private copy constructor:
private:
Derived(const Derived & ref) : Base(ref) { std::cout << "Derived copy constructor"; }
}
Base * obj = new Derived;
Base * obj2 = obj->clone();
Đoạn mã trên sẽ tạo ra kết quả:
"Base copy constructor"
"Derived copy constructor"
Nói cách khác, các đối tượng đó được xây dựng vào loại mong muốn " Có nguồn gốc ", và không thuộc loại" Base "!
Như bạn có thể thấy, trong kiểu gốc, trình tạo bản sao được cố tình tạo riêng tư, vì nó sẽ là thiết kế API xấu để cho các lập trình viên khả năng vô tình cố gọi hàm sao chép theo cách thủ công, thay vì sử dụng giao diện thông minh được cung cấp bởi clone(). Nói một cách khác, một hàm tạo bản sao có thể gọi trực tiếp có thể khiến các lập trình viên mắc sai lầm được đề cập trong phần 1. Trong trường hợp này, thực hành tốt nhất sẽ có hàm khởi tạo sao chép được ẩn và chỉ truy cập gián tiếp bằng cách sử dụng phương thức "sao chép" () ".
Nguồn
2011-07-25 03:23:41
Không có điều gì như một hàm tạo gán, bạn có ý là di chuyển hàm tạo không? – Praetorian
đó là lỗi đánh máy ... sửa ngay bây giờ ... nhà điều hành chuyển nhượng –
lý do chính tôi hỏi câu hỏi đó là tôi đã đọc sách C++ và tự mình học C++ ... và sách tôi đang đọc Lippman , Lajoie C++ Primer và Stroustrup và những người khác không cung cấp đủ các ví dụ thế giới thực, nơi cần có một cách tiếp cận như vậy. tất nhiên, không thể cung cấp danh sách đầy đủ ... nhưng một vài trường hợp cách tiếp cận như vậy sẽ hữu ích có thể được minh họa (ví dụ: ví dụ về xe hơi bằng @tc) và tôi đã tuyên bố rằng không có con trỏ hoặc liên kết với đối tượng duy nhất như một tập tin ....... –