views:

101

answers:

3

I have defined a Cloneable interface:

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

I have also some other interface classes (content not relevant to issue):

struct Interface
{
};

struct Useful_Goodies
{
};

I have created a leaf object which inherits from the above classes:

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

I'm getting the error:

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

If I change the type to Cloneable *, I get this error message:

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

My Questions (all related):

  1. How can the leaf class resolve the requirements of the Cloneable interface?
  2. Is there a better solution to implement a Cloning contract, where all objects are guaranteed to implement cloning?

I'm using this paradigm as part of generic programming (records, fields & database).

Compiler: MS Visual Studio 2008; Platforms: Windows XP & Vista

+2  A: 

Having your clone function return a Cloneable * is correct.

You will get an ambiguous conversion if one of your interfaces also derives from Cloneable.

Edit: Alf points out in the comments that not only is it possible for Leaf::clone to return a Leaf*, it's actually preferable for it to do so. I stand corrected.

Mark Ransom
I found one of the interfaces was also inheriting from Cloneable as virtual. The "main" inheritance line was inheriting from Cloneable but not virtual.
Thomas Matthews
Alf P. Steinbach
@Alf, I must disagree. The function is defined as returning a `Cloneable*` in the base class, so that is what it must return. Of course you will want to create a `Leaf*` to return, but it must be cast to the proper type before returning, especially when multiple inheritance is involved. If the caller already knows which kind of class is being returned, it could use a copy constructor and avoid the `clone` method altogether for superior type checking.
Mark Ransom
Alf P. Steinbach
@Alf: amazing that there's still corners of the C++ language that make me look like an ignorant fool. Thanks for the link.
Mark Ransom
+1  A: 

You probably failed to mention that Interface or some other base class also inherits Cloneable. The "ambiguous conversion" means Leaf probably contains multiple Cloneable base class subobjects. (A problem with covariant return type could be a direct result of the same problem.)

You'll want to solve this problem using virtual inheritance (recommended and linked reading: C++ FAQ Lite topics 25.8 through 25.13). To start with, change all instances of : public Cloneable to : public virtual Cloneable.

aschepler
+1  A: 

I can risk and say that you are probably non virtually inheriting from Cloneable from more than one path. That is, some of your other base besides the direct Cloneable inherits (directly or indirectly) from Cloneable. This makes the conversion from Leaf* to Cloneable* ambiguous as there are more than one Cloneable base in your Leaf.

The simple solution is using virtual inheritance from the interface:

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

Virtual inheritance means that even if both Interface and Test inherit from Cloneable, there is only a single Cloneable base object.

David Rodríguez - dribeas