2015-06-05 16 views
7

Tôi có một lớp A (từ thư viện mà tôi không có quyền kiểm soát) với phương thức sao chép riêng và phương thức clone và lớp học bắt nguồn từ B từ A. Tôi cũng muốn thực hiện clone cho B.Trình tạo bản sao bị xóa hoàn toàn vì định nghĩa mặc định sẽ bị lỗi

Cách tiếp cận ngây thơ

#include <memory> 

class A { // I have no control here 
    public: 
    A(int a) {}; 

    std::shared_ptr<A> 
     clone() const 
     { 
     return std::shared_ptr<A>(new A(*this)); 
     } 

    private: 
    A(const A & a) {}; 
}; 

class B: public A { 
    public: 
    B(int data, int extraData): 
     A(data), 
     extraData_(extraData) 
    { 
    } 

    std::shared_ptr<B> 
    clone() const 
    { 
     return std::shared_ptr<B>(new B(*this)); 
    } 

    private: 
    int extraData_; 
}; 

int main() { 
    A a(1); 
} 

Tuy nhiên, thất bại, kể từ khi các nhà xây dựng bản sao của A là tin:

main.cpp: In member function ‘std::shared_ptr<B> B::clone() const’: 
main.cpp:27:42: error: use of deleted function ‘B::B(const B&)’ 
    return std::shared_ptr<B>(new B(*this)); 
            ^
main.cpp:17:7: note: ‘B::B(const B&)’ is implicitly deleted because the default definition would be ill-formed: 
class B: public A { 
    ^
main.cpp:14:5: error: ‘A::A(const A&)’ is private 
    A(const A & a) {}; 
    ^
main.cpp:17:7: error: within this context 
class B: public A { 

Ở đó tôi có thể là một cách để tận dụng A::clone() cho B::clone(), nhưng chắc không chắc làm thế nào điều này sẽ làm việc chính xác. Bất kỳ gợi ý nào?

Trả lời

2

Bạn cần phải thực hiện sao chép constructor của A bảo vệ để các lớp có nguồn gốc có thể sử dụng nó:

protected: 
    A(const A & a) { /*...*/ } 

Hy vọng rằng sẽ giúp.

+0

Tôi không thể kiểm soát 'A' vì thư đến từ thư viện; Tôi đã làm rõ điều này trong bài đăng gốc. –

+1

Sau đó, bạn không nên bắt nguồn từ 'A'. – Peter

+0

@ NicoSchlömer: Ohh .. trong trường hợp đó, đó là một ý tưởng tồi để lấy được từ 'A'. Bạn nên sử dụng bố cục ngay bây giờ, thay vì thừa kế. – Nawaz

1

Lý do định nghĩa mặc định của B 's copy constructor là vô hình thành là vì - nếu nó được phép - nó sẽ gọi constructor sao chép tư nhân (do đó không thể tiếp cận để B) và không được định nghĩa của A.

Làm cho bản dựng của bản sao của A được bảo vệ hoặc công khai, do đó có thể truy cập B. Một tùy chọn khác (thực sự xấu) là khai báo lớp B làm bạn của A. Tất cả các khả năng cũng sẽ yêu cầu bạn cung cấp một định nghĩa cho hàm tạo bản sao của A.

+0

Tôi không có quyền kiểm soát A vì thư đến từ thư viện; Tôi đã làm rõ điều này trong bài đăng gốc. –

+0

Theo nhận xét tôi đã thực hiện để đáp ứng với sự làm rõ đó (bên dưới bài viết của Nawaz) có một hàm tạo riêng là một gợi ý khá đáng kể rằng bạn không nên bắt nguồn từ 'A'. – Peter

+0

Không có cách nào để sử dụng 'A :: clone()'? –

3

Tôi cho rằng đó là lỗi đánh máy mà B của bạn hoàn toàn không có thành viên nào, và bạn thiếu public: trước định nghĩa B::B(int,int).

Tác giả của lớp được đại diện bởi A của bạn dường như muốn nó là có thể sao chép nhưng không sao chép được. Điều đó sẽ gợi ý anh ta hoặc cô ấy muốn tất cả các trường hợp để sống trên heap. Nhưng ngược lại, có một nhà xây dựng công khai công khai A::A(int). Bạn có chắc là bạn đúng về điều đó không?

Giả sử rằng lớp học có thể tiết lộ đủ thông tin về một trường hợp cụ thể để tạo thành một thể hiện khác. Ví dụ, đặt một chút thịt thêm về A:

class A { 
public: 
    A(int a) 
    : data_(a){}; 

    std::shared_ptr<A> 
    clone() const 
    { 
     return std::shared_ptr<A>(new A(*this)); 
    } 

    int data() const { 
     return data_; 
    } 

private: 
    A(const A & a) {}; 
    int data_; 
}; 

Và nếu đó là sự thật, sau đó các nhà xây dựng cộng đồng sẽ làm cho nó chỉ bất tiện để phá vỡ các tư nhân, không xác định bản sao constructor:

A a0(1); 
A a1{a0.data()};  // Inconvenient copy construction 

Vì vậy, tôi ít tự tin rằng A trung thành đại diện cho vấn đề lớp học. Tuy nhiên, lấy câu hỏi theo mệnh giá, câu hỏi bạn cần trả lời là: Thậm chí bạn có thể sao chép một cách bất tiện một cấu hìnhA không?

Nếu không thì bạn bị kẹt. Nếu vậy, bạn có thể sử dụng bản sao bất tiện xây dựng A để xác định rõ ràng một hàm tạo bản sao thông thường cho B, đó là tất cả những gì bạn cần. Ví dụ.

class B: public A { 
public: 
    B(B const & other) 
    : A(other.data()),extraData_(other.extraData_){}  

    B(int data, int extraData): 
    A(data), 
    extraData_(extraData) 
    { 
    } 

    std::shared_ptr<B> 
    clone() const 
    { 
     return std::shared_ptr<B>(new B(*this)); 
    } 

    int extradata() const { 
     return extraData_; 
    } 

private: 
    int extraData_; 
}; 

#include <iostream> 

int main() 
{ 
    B b(1,2); 
    std::shared_ptr<B> pb = b.clone(); 
    std::cout << pb->data() << std::endl; 
    std::cout << pb->extradata() << std::endl; 
    return 0; 
} 
Các vấn đề liên quan