2015-06-05 1 views
7

У меня есть класс A (из библиотеки, над которой у меня нет контроля) с помощью частного конструктора копирования и метода clone, а также производного класса B от A. Я хотел бы реализовать clone для B.конструктор копирования неявно удаляется, потому что определение по умолчанию будет плохо сформировано

Наивный подход

#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); 
} 

однако, не удается, так как конструктор копирования из A является частным:

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 { 

Там может способ использовать A::clone() для B::clone(), но я не знаю, как это будет работать. Любые намеки?

ответ

2

Вы должны сделать копию-конструктор A защищенного таким образом, что производный класс может использовать:

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

Надежда, что помогает.

+0

У меня нет контроля над 'A', поскольку он исходит из библиотеки; Я разъяснил это в оригинальной публикации. –

+1

Тогда вам не следует выводить из 'A'. – Peter

+0

@ NicoSchlömer: Ох .. в этом случае это плохая идея, чтобы получить от 'A'. Теперь вы должны использовать композицию вместо наследования. – Nawaz

1

Причина определения по умолчанию B конструктор копирования плохо сформирован потому, что - если это было разрешено - было бы ссылаться на частные (поэтому недоступны для B) и не определен конструктор копий A.

Сделать конструктор копии A защищенным или общедоступным, поэтому он доступен для B. Другой (очень плохой) вариант заключается в объявлении класса B в качестве друга A. Все возможности также потребуют предоставить определение для конструктора копирования A.

+0

У меня нет контроля над А, поскольку он исходит из библиотеки; Я разъяснил это в оригинальной публикации. –

+0

В соответствии с комментариями, сделанными мной в ответ на это разъяснение (ниже сообщения Nawaz), имеющим частный конструктор, довольно важный намек на то, что вы не должны извлекаться из 'A'. – Peter

+0

Нет ли способа использовать 'A :: clone()' либо? –

3

Я полагаю, что это опечатка, что ваш B не имеет открытых членов на всех, и что Вы пропускаете public: перед определением B::B(int,int).

Автор класса, представленный вашим A, по-видимому, хочет, чтобы он был клонированным, но не скопированным конструктивным. Это предполагает, что он или она хочет, чтобы все экземпляров жили в куче. Но наоборот, есть общественность конструктор A::A(int). Вы уверены, что вы правы в этом?

Допустимо предположить, что класс может выявить достаточно информации о данном экземпляре, чтобы составить другой экземпляр. Например, поставив немного больше плоти на 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_; 
}; 

И если это верно, то общественный конструктор сделает это просто неудобно обходить частный, неопределенный конструктор копирования:

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

Поэтому я не уверен, что A точно представляет проблему класс. Принимая его по номинальной стоимости, однако, вопрос, который вам нужен, должен ответить : Можете ли вы даже неудобно скопировать конструкциюA?

Если нет, то вы застряли. Если это так, то вы можете использовать неудобную копию для строительства A, чтобы явно определить обычный конструктор копирования для B, , который вам нужен. Например.

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; 
} 
Смежные вопросы