0

I have the following class structure:

class DBData
{

    public:

    DBData();

    virtual
    ~DBData() = 0;

    virtual
    DBData* Clone() const = 0;

    virtual
    std::unique_ptr<DBData>& Clone() const = 0;

};

This does no compile, and the compiler objects with the following error message:

error: ‘virtual std::unique_ptr<DBData>& DBData::Clone() const’ cannot be overloaded with ‘virtual DBData* DBData::Clone() const’

Why does this error occur? My guess would be that it has something to do with both return types being either references or pointers (which are in some ways similar).

Or possibly unique_ptr is too similar to a raw pointer, but that doesn't seem to make a lot of sense to me.

Obvious Solution:

Obvious problem obvious solution. Should have realized this. Taking inspiration from operator++:

virtual
std::unique_ptr<DBData>& Clone(int dummy = 0) const = 0;

Or perhaps better, just rename it:

virtual
std::unique_ptr<DBData>& CloneUniquePtr() const = 0;

Edit: Nope - this doesn't work either.

The reason being that this

virtual
std::unique_ptr<DBDataDerived>& CloneUniquePtr() const;

is an invalid covariant return type. Given that this is a reference type, I thought this should be ok. Is it the case that only raw pointers can be covariant return types?

Edit 2: For a type to be covariant (in this context at least) it has to obey Liskov Substitution Principle.

It seems the only way to write something compilable is to do:

std::unique_ptr<DBData> DBDataDerived::Clone() const;

Which means not using covariant return types at all.

FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
  • you cannot overload by return type. – apple apple May 15 '22 at 12:23
  • If you had `std::unique_ptr Clone()` and `int* Clone(int = 0);`, attempt to call `Clone();` would result in "ambiguous call" error. Rename is probably the only viable option. – Yksisarvinen May 15 '22 at 12:40
  • Returning a `unique_ptr` by reference in `CloneUniquePtr` smells pretty weird to me. Where is the referred-to `unique_ptr` living? – Nathan Pierson May 15 '22 at 13:15
  • @NathanPierson The `unique_ptr` should be owned by the caller of the `Clone` function. Does that answer your question? – FreelanceConsultant May 15 '22 at 14:52
  • It does not. If the `CloneUniquePtr` is going to return a reference, it needs to be a reference _to something_, and I'm trying to figure out what that something is if not "a dangling reference to a local variable of `CloneUniquePtr`." Telling me that the caller of `Clone`--by this do you mean the original `Clone` or the distinct `CloneUniquePtr`?--should own it doesn't answer this. There are some [questions](https://stackoverflow.com/questions/37788255/clonable-class-hierarchy-and-unique-ptr) about `unique_ptr` and covariance. – Nathan Pierson May 15 '22 at 17:36
  • @NathanPierson I see your point - I checked what I have written and it seems I was returning by value. I guess I must have changed it after posting this question. Initially my thought process was if I am to return something it must be a reference or pointer type. – FreelanceConsultant May 15 '22 at 18:39

1 Answers1

0

The problem is that we cannot overload a member function(or a function) based only on its return type.

This is because overload resolution takes into account the function's signature.

And from defns.signature.member

signature 〈class member function〉 name, parameter type list (11.3.5), class of which the function is a member, cv-qualifiers (if any), and ref-qualifier (if any)

As we can see the return type isn't part of the signature of the member function. Hence it(the return type) cannot be used to overload the member function.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • Ah yes how stupid of me. I was thrown off by the fact I had just written a `Clone` function with a different return type in each class which inherts from the base. In fact, in the back of my mind I was thinking I need to overload this with a dummy `int` argument. – FreelanceConsultant May 15 '22 at 12:32