Как избежать шаблонного кода clone () для полиморфных объектов в c ++ - PullRequest
4 голосов
/ 08 июня 2011

Если я хочу клонировать полиморфный объект в C ++ (т. Е. Экземпляр класса A, который является производным от некоторого другого класса B), кажется, что самый простой способ дать B виртуальную функцию-член-клон, которая должна быть переопределена А так выглядит

A* clone(){
    return new A(*this);
}

Моя проблема в том, что я нахожу этот ненужный шаблонный код, поскольку он почти всегда необходим, если кто-то хочет использовать полиморфные функции C ++ во время выполнения. Как это можно обойти?

Спасибо

Зачем мне это нужно:

Мой вариант использования может быть абстрагирован до следующего примера: У меня есть class Integral, который оценивает интеграл некоторой функции. Сделайте это, у них есть член, который является указателем на class MathFunction. Этот абстрактный класс содержит чисто виртуальную функцию evaluate, которая принимает один аргумент. Я хотел реализовать функцию власти Я бы создал class PowFunction : class MathFunction. Этот класс будет иметь член exponent, а функция оценки будет выглядеть следующим образом:

double evaluate(x){
    return pow(x,exponent);
}

Как уже говорилось, член MathFunction из class Integral должен быть полиморфным, что требует указателя. Ответить на вопросы комментаторов с другим вопросом. Почему бы мне не захотеть делать копии объектов MathFunction?

Я действительно хочу, чтобы Integral «владел» своей MathFunction, что означает, что он может изменять параметры (например, exponent) без изменения MathFunction любого другого объекта Integral. Это означает, что каждый Интеграл должен иметь свою собственную копию. Для этого требуется функция clone () для MathFunctions, не так ли?

Одна альтернатива, о которой я подумал: если несколько объектов Integral могут совместно использовать одну и ту же MathFunction через указатель на один и тот же адрес, я мог бы создавать копии объектов Integral без необходимости копировать MathFunction. Но в этом случае мне пришлось бы сделать все свойства постоянными или как-то только для чтения, что тоже не очень элегантно. Кроме того, какой объект Integral должен обрабатывать удаление объекта MathFunction?

Зачем вам это нужно:

Вы серьезно говорите, что как только вы работаете с полиморфными объектами, вам никогда не понадобится операция копирования? Что отличает полиморфный объект от других объектов в этом отношении?

Используя эту аргументацию, вы также можете выбросить конструктор копирования и оператор присваивания копии из стандарта C ++!

Ответы [ 2 ]

9 голосов
/ 08 июня 2011

Уменьшите необходимость клонировать полиморфные объекты. На самом деле, я редко нахожу необходимость в этом в своем собственном коде, и комментарии к вопросу говорят о том, что я едва ли одинок во мнении, что, если вы обнаружите, что все клонируете, вы, вероятно, спроектируете это неправильно.

Конечно, чтобы быть бесполезным, вы действительно можете использовать шаблон любопытно повторяющихся шаблонов.

template<typename T> struct Clone {
    virtual T* clone() { return new T(static_cast<const T&>(*this)); }
};
3 голосов
/ 08 июня 2011

Я решил эту проблему с помощью макроса ... это ужасно, но работает, чтобы избежать несоответствий.

/** An interface that can be inherited by any class that wants to provide a Clone()
  * method that will return a copy of itself.
  */
class ICloneable
{
public:
   ICloneable() {}
   virtual ~ICloneable() {}

   virtual ICloneable * Clone() const = 0;
};
#define DECLARE_STANDARD_CLONE_METHOD(class_name) virtual ICloneable * Clone() const {new class_name(*this);}

[...]
public MyCloneableClass : public ICloneable
{
public:
   MyCloneableClass() {}

   DECLARE_STANDARD_CLONE_METHOD(MyCloneableClass);
};
...