2016-04-07 5 views
0

Предположим, что у меня есть установка с абстрактного класса ApplicatonBase, который имеет unique_ptr к другой абстрактный класс DocumentBase:Factory Method шаблон с unique_ptr члена абстрактного класса и конструктор копирования

class ApplicationBase 
{ 
public: 

    void factoryMethod() 
    { 
     _doc->doSomething(); 
    }; 

protected: 
    std::unique_ptr<DocumentBase> _doc; 

}; 

class DocumentBase 
{ 
public: 
    virtual void doSomething() = 0; 
}; 

Сейчас я разработке конкретных классов RichDocument и RichApplication следующим образом:

class RichDocument : public DocumentBase 
{ 
public: 
    void doSomething() override 
    { 
     std::cout << "I'm rich document\n"; 
    } 
}; 

class RichApplication : public ApplicationBase 
{ 
public: 
    RichApplication() 
    { 
     _doc = std::unique_ptr<RichDocument>(new RichDocument()); 
    } 

    RichApplication(const RichApplication& other) 
    { 
     /* 
     * TODO: I want to copy the data from other document 
     *  unique_ptr and give it to the current document 
     *  unique_ptr 
     */ 

     //Following crashes as the copy constructor is not known: 
     // error: no matching function for call to ‘RichDocument::RichDocument(DocumentBase&) 
     //_doc.reset(new RichDocument(*other._doc)); 
    } 
}; 

Проблема заключается в конструкторе копирования. Я хочу глубоко скопировать данные в unique_ptr в конструкторе копирования. Есть ли способ сделать это? Или я должен изменить свою структуру? Любая помощь будет оценена по достоинству.

+0

вы можете определить виртуальный 'unique_ptr DocumentBase :: клон () '. Или вы можете использовать статический полиморфизм (например, 'template class Application {...' (обратите внимание, что переход к статическому полиморфизму является большим решением, которое потребует совершенно другого способа структурирования вашего кода) – enobayram

+0

@enobayram См. Следующие путь: класс 'DocumentBase { ... виртуальный станд :: unique_ptr клон() Const { возвращение станд :: unique_ptr (новый DocumentBase (* это)); }; }; ' и ' class RichDocument: public DocumentBase { ... virtual std :: unique_ptr clone() const { return std :: unique_ptr (новый RichDocument (* this)); } }; ' Ошибки компилятора бит: не может выделить объект абстрактного типа DocumentBase. Это из-за чистой виртуальной функции. Любое обходное решение? –

+0

@enobayram Даже если в приведенных выше методах клонирования я удаляю абстрактность класса, у меня есть следующая ошибка: Недопустимый тип возвращаемого значения covariant для 'virtual std :: unique_ptr RichDocument :: clone() –

ответ

1

Поскольку вы подключаете до RichDocument и RichApplication в иерархии классов, вы должны быть готовы выполнить одно из следующих действий:

  • Принять любой базовый документ при создании богатого документа или
  • Отклонить все документы, кроме RichDocument.

Предполагая, что единственный способ для инициализации _doc в конструкторе RichApplication, то второй подход должен быть достаточно хорош:

RichDocument *otherDoc = dynamic_cast<RichDocument*>(other._doc.get()); 
// We created RichDocument in the constructor, so the cast must not fail: 
assert(otherDoc); 
_doc.reset(new RichDocument(*otherDoc)); 
+0

В чем смысл использования 'dynamic_cast', если вы не собираетесь проверять результат? Почему бы просто не использовать 'static_cast' вместо этого? – enobayram

+0

@enobayram Когда 'dynamic_cast' возвращает' nullptr', вы в значительной степени гарантируете сбой на следующей строке. Когда 'static_cast' терпит неудачу, потому что тип неправильный, программа может произойти сбой в другом месте. Я думаю, что явное утверждение не повредит. – dasblinkenlight

+0

Я бы не был так уверен в аварии. f.x в этом конкретном случае, скорее всего, это не сбой, так как «RichDocument» не имеет членов, поэтому конструктор копирования не будет следовать за нулевым указателем. – enobayram

 Смежные вопросы

  • Нет связанных вопросов^_^