Как клонировать объект множественного наследования? - PullRequest
1 голос
/ 15 октября 2010

Я определил интерфейс Cloneable:

struct Cloneable
{
  virtual Cloneable * clone(void) const = 0;
}

У меня также есть некоторые другие классы интерфейса (содержимое не относится к проблеме):

struct Interface
{
};

struct Useful_Goodies
{
};

Я создал объект листа, которыйнаследует от вышеуказанных классов:

struct Leaf : public Cloneable, public Interface, public Useful_Goodies
{
  Leaf * clone(void) const  // Line #1 for discussion.
  {
     return new Leaf(*this);
  }
};

Я получаю сообщение об ошибке:

overriding virtual function return type differs and is not covariant from 'Cloneable::clone'

Если я изменю тип на Cloneable *, я получу это сообщение об ошибке:

'return' : ambiguous conversions from 'Leaf *' to 'Cloneable *'

Мои вопросы (все связанные):

  1. Каким образом листовой класс может соответствовать требованиям интерфейса Cloneable?
  2. есть лучшее решение для реализации контракта на клонирование, где все объекты гарантированно реализуют клонирование?

Я использую эту парадигму как часть общего программирования (записи, поля и базы данных).

Компилятор: MS Visual Studio 2008;Платформы: Windows XP и Vista

Ответы [ 3 ]

2 голосов
/ 15 октября 2010

Если ваша функция clone возвращает Cloneable *, это правильно.

Вы получите неоднозначное преобразование, если один из ваших интерфейсов также получен из Cloneable.

Редактировать: Альф указывает в комментариях, что не только Leaf::clone может вернуть Leaf*, но на самом деле это предпочтительно.Я исправлен.

1 голос
/ 15 октября 2010

Я могу рискнуть и сказать, что вы, вероятно, фактически не наследуете от Cloneable от более чем одного пути.То есть, некоторые другие ваши базы, кроме прямой Cloneable, наследуют (прямо или косвенно) от Cloneable.Это делает преобразование из Leaf* в Cloneable* неоднозначным, поскольку в вашем Leaf имеется более одной Cloneable базы.

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

struct Cloneable {
   virtual Cloneable * clone() = 0;
};
struct Interface : virtual Cloneable {
};
struct Test : virtual Cloneable, Interface {
   virtual Test* clone() {
      return new Test(*this);
   }
};

Виртуальное наследование означает, что даже если и Interface, и Test наследуют от Cloneable, существует толькоодин Cloneable базовый объект.

1 голос
/ 15 октября 2010

Вы, вероятно, не упомянули, что Interface или какой-либо другой базовый класс также наследует Cloneable.«Неоднозначное преобразование» означает, что Leaf, вероятно, содержит несколько подобъектов базового класса Cloneable.(Проблема с ковариантным типом возврата может быть прямым результатом той же проблемы.)

Вы захотите решить эту проблему, используя виртуальное наследование (рекомендуемое и связанное чтение: C ++ FAQ Liteтемы с 25,8 по 25,13).Для начала измените все экземпляры : public Cloneable на : public virtual Cloneable.

...