2016-07-21 8 views
0

Я немного зациклен на том, как вы достигнете чего-то подобного на C++. У меня такое чувство, что это может быть связано с моей архитектурой.
Предположим, у меня есть гараж в Монреале, и в этом гараже есть разные машины. Обычно я бы пошел с вектором указателей на автомобиль базового класса. Вот проблема, хотя, я тогда хочу глубоко скопировать гараж и открыть его в Майами. Кроме того, у автомобилей Saab должен быть другой конструктор копий, но с той же подписью. Будут другие исключения, подобные этому по дороге. Я не знаю, что в гараже заранее. Вот код, который у меня есть.Хранить переменное количество объектов переменного числа производного класса и глубоко скопировать их

 //base class 
     class Car 
     { 
      public: 

       Car(int speed); 

      private: 
       int speed; 

     } 
     class Garage 
     { 
       public: 
         Garage(){}; 
         //copy constructor of the garage 
         Garage(const Garage &toCopy) 
         { 
         for(int i=0;i<toCopy.cars.size();i++) 
         { 
         ReceiveCar(*cars[i]); 
         } 
         } 
         vector<std::shared<Car>> cars; 
         template <typename T> 
         T* ReceiveCar() 
         { 
         std::shared_ptr<T> ptr = std::make_shared<T>(); 
         cars.push_back(ptr); 
         return ptr.get(); 
         } 
         T* ReceiveCar(Car &toCopy) 
         { 
         std::shared_ptr<T> ptr = std::make_shared<T>(toCopy)      cars.push_back(ptr); 
         return ptr.get(); 
         } 

      } 
     class Saab : public Car 
    { 
     public: 
       Saab(int speed) 
       :Car(speed) 
       { 
       DoWork(); 
       }; 
    } 
    class AstonMartin: public Car 
    { 
     public: 
       AstonMartin(int speed) 
        :Car(speed) 
       { 
       DoImportantStuff(); 
       }; 
       AstonMartin(const AstonMartin& toCopy) 
        :Car(toCopy.speed) 
       { 
       DoImportantStuff(); 
       }; 
    } 

Конечно, используемый конструктор копирования является неявным из автомобиля. Можно ли назвать производный класс «одним» вместо динамического кастинга между ifs/elses для каждого исключения в правиле. Может быть, как-нибудь сохранить каждый производный класс с указателем?
PS: Я знаю, что я не должен возвращать исходные указатели, но деструкторы для автомобилей являются частными в моем коде, поэтому shared_pointers по-прежнему безопасны.

+1

Посмотрите на виртуальный клон. – Jarod42

+0

Как насчет использования простого контейнера типа 'std :: vector'? –

+1

dupe of http://stackoverflow.com/questions/5148706/copying-a-polymorphic-object-in-c или http://stackoverflow.com/questions/5731217/how-to-copy-create-derived-class -instance-from-a-pointer-to-polymorphic-base-c – NathanOliver

ответ

1

В контексте наследования конструктор копирования должен быть сконструирован как так называемый «виртуальный экземпляр копии». Эти функции называются часто copySelf, cloneSelf или просто клонированы.

Вот Ваш развернутый пример использования конструкторы копирования и конструктор виртуальной копии:

#include <memory> 
#include <iostream> 
#include <vector> 
using std::cout; 
using std::endl; 
using std::vector; 

//base class 
class Car 
{ public: 
    Car(int speed): speed(speed) {}; 
    Car(const Car& c): speed(c.speed) 
    { cout <<"Copy Constructor Car" <<endl; 
    } 
    virtual void display() 
    { cout <<" speed: " <<speed <<endl; 
    } 
    virtual Car* clone()const =0; // virtual copy constructor 
    private: 
    int speed; 
}; 
typedef std::shared_ptr<Car> CarP; 
class Garage 
{ private: 
    vector<CarP> cars; 
    public: 
    Garage() {} 
    //copy constructor of the garage 
    Garage(const Garage &toCopy) 
    { cout <<"Copy Constructor Garage" <<endl; 
     for (CarP c : toCopy.cars) 
     { CarP cp(c->clone()); 
     ReceiveCar(cp); 
     } 
    } 
    void ReceiveCar(CarP toCopy) 
    { cars.push_back(toCopy); 
    } 
    void display() 
    { for (CarP c : cars) c->display(); 
    } 
}; 
class Saab: public Car 
{ public: 
    Saab(int speed): Car(speed) 
    { cout <<"Constructor Saab" <<endl; 
    } 
    void display() 
    { cout <<"Car: Saab"; Car::display(); 
    } 
    Saab* clone()const 
    { return new Saab(*this); 
    } 
}; 
class AstonMartin: public Car 
{ public: 
    AstonMartin(int speed): Car(speed) 
    { cout <<"Constructor AstonMartin" <<endl; 
    } 
    AstonMartin(const AstonMartin& toCopy): Car(toCopy) 
    { cout <<"Copy Constructor AstonMartin" <<endl; 
    } 
    void display() 
    { cout <<"Car: AstonMartin"; Car::display(); 
    } 
    AstonMartin* clone()const 
    { return new AstonMartin(*this); 
    } 
}; 
int main() 
{ 
    CarP saab =std::make_shared <Saab>(100); 
    CarP aston =std::make_shared <AstonMartin>(200); 
    Garage montreal; 
    montreal.ReceiveCar(saab); 
    montreal.ReceiveCar(aston); 
    montreal.display(); 
    Garage miami(montreal); // your decision to offer the user a copy constructor: 
    miami.display(); 
} 

производится выход:

Constructor Saab 
Constructor AstonMartin 
Car: Saab speed: 100 
Car: AstonMartin speed: 200 
Copy Constructor Garage 
Copy Constructor Car 
Copy Constructor Car 
Copy Constructor AstonMartin 
Car: Saab speed: 100 
Car: AstonMartin speed: 200 
2

Обычным решением является виртуальный метод clone(), который вы вызываете, чтобы сделать копию объекта, а не использовать конструктор копирования.

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

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