1

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

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
  • I used the same compiler, everything compiles fine. This was a bug, resolved VC6 onwards . – DumbCoder Oct 15 '10 at 16:15
  • There's something you're not telling us, because this code compiles fine for me in VS 2008. –  Oct 15 '10 at 16:30
  • The real question if why do you need to clone an object. I see a lot f this from Java converts (where it is a big problem/concept) but I have yet to see the need in c++ code. An explanation of what you are actually trying to achieve may give you some good advice on c++ techniques, – Martin York Oct 15 '10 at 16:30
  • @Martin York: I find that this is especially common when creating dynamic language tools such as interpreters, to fill the need for a copy constructor that can be invoked dynamically. I haven't found any other valid use for it yet, but that doesn't mean one doesn't exist. I prefer to give people the benefit of the doubt, tempting though it may always be to intervene. – Jon Purdy Oct 15 '10 at 17:53

3 Answers3

2

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
  • 299,747
  • 42
  • 398
  • 622
  • 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 Oct 15 '10 at 18:04
  • yes, but returning `Leaf*` is also correct, and far more practical. Returning `Cloneable*` is a Java-ism. In C++ one should use the most specific types available, for static type checking. The OPs problem was/is apparently in the information he didn't provide. Namely use of an archaic pre-standard compiler (or possibly something else). Cheers & hth., – Cheers and hth. - Alf Oct 15 '10 at 18:28
  • @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 Oct 15 '10 at 19:05
  • 2
    No, that's incorrect. This is sort of novice level so I'm sending you to the FAQ instead of quoting the standard. See the explanation of C++ "covariant" function results in FAQ item ["20.8 What is a "virtual constructor"?"](http://www.parashift.com/c++-faq-lite/virtual-functions.html)". Uhm, while I'm throwing links about I might as well reference my own blog entry on [how to implement cloning in a reusable way](http://alfps.wordpress.com/2010/06/12/cppx-3-ways-to-mix-in-a-generic-cloning-implementation/). :-) Cheers & hth., – Cheers and hth. - Alf Oct 15 '10 at 19:11
  • @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 Oct 15 '10 at 19:38
1

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
  • 70,891
  • 9
  • 107
  • 161
1

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
  • 204,818
  • 23
  • 294
  • 489