1

Я определил 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 & Виста

+0

Я использовал тот же компилятор, все прекрасно компилируется. Это была ошибка, разрешенная VC6 и далее. – DumbCoder

+0

Что-то вы нам не рассказываете, потому что этот код компилируется для меня в VS 2008. –

+0

Реальный вопрос, зачем вам клонировать объект. Я вижу много это из конверсий Java (где это большая проблема/концепция), но я еще не вижу необходимости в коде C++. Объяснение того, что вы на самом деле пытаетесь достичь, может дать вам некоторые полезные советы по методам C++, –

ответ

2

После вашей clone функции возвращают Cloneable * правильно.

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

Edit: Alf указывает в комментариях, что не только возможно для Leaf::clone вернуть Leaf*, это на самом деле предпочтительнее для него, чтобы сделать это. Я стою исправлено.

+0

Я обнаружил, что один из интерфейсов также наследуется от Cloneable как виртуальный. «Основная» линия наследования наследовалась от Cloneable, но не виртуальна. –

+0

Да, но возврат 'Leaf *' также верен и гораздо более практичен. Возвращение 'Cloneable *' является Java-ism. В C++ следует использовать наиболее доступные типы, для проверки статического типа. Проблема OPs была/по-видимому, в информации, которую он не предоставил. А именно использование архаичного предстандартного компилятора (или, возможно, что-то еще). Cheers & hth., –

+0

@Alf, я должен не согласиться. Функция определяется как возвращение «Cloneable *» в базовый класс, так что это то, что он должен вернуть. Конечно, вы захотите создать «Лист *» для возврата, но перед возвратом его нужно перевести в соответствующий тип, особенно когда задействовано множественное наследование. Если вызывающий абонент уже знает, какой тип класса возвращается, он может использовать конструктор копирования и вообще избегать метода «clone» для проверки превосходного типа. –

1

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

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

1

Я могу рискнуть и сказать, что вы, вероятно, практически не наследуете от 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 базовый объект.

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