Как скопировать / создать экземпляр производного класса из указателя на полиморфный базовый класс? - PullRequest
26 голосов
/ 20 апреля 2011

Я долго боролся с такого рода проблемами, поэтому решил спросить здесь.

class Base {
  virtual ~Base();
};
class Derived1 : public Base { ... };
class Derived2 : public Base { ... };
...

// Copies the instance of derived class pointed by the *base pointer
Base* CreateCopy(Base* base);

Метод должен возвращать динамически созданную копию или, по крайней мере, сохранять объект в стеке в некоторой структуре данных, чтобы избежать проблемы «возврата адреса временной».

Наивный подход для реализации вышеуказанного метода заключается в использовании нескольких typeid с или dynamic_cast с в ряде операторов if для проверки каждого возможного производного типа и последующего использования оператора new. Есть ли другой, лучший подход?

П.С .: Я знаю, что этой проблемы можно избежать, используя умные указатели, но мне интересен минималистичный подход без набора библиотек.

Ответы [ 2 ]

39 голосов
/ 20 апреля 2011

Вы добавляете virtual Base* clone() const = 0; в свой базовый класс и соответствующим образом реализуете его в своих производных классах.Если ваш Base не является абстрактным, вы, конечно, можете вызвать его конструктор копирования, но это немного опасно: если вы забудете реализовать его в производном классе, вы получите (вероятно, нежелательный) срез.1004 * Если вы не хотите дублировать этот код, вы можете использовать CRTP идиома для реализации функции через шаблон:

template <class Derived>
class DerivationHelper : public Base
{
public:
  virtual Base* clone() const
  {
    return new Derived(static_cast<const Derived&>(*this)); // call the copy ctor.
  }
};

class Derived1 : public DerivationHelper <Derived1> { ... };
class Derived2 : public DerivationHelper <Derived2> { ... };
1 голос
/ 20 апреля 2011

Альтернативой является наличие чисто виртуального CreateCopy() метода в общей базе, который реализован в каждом производном классе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...