c++ virtual class function returning instance of concrete subclass

Viewed 141

What I would like, if not with this syntax, but in spirit :

class A
{
   virtual A f()=0;
};

class B : public A
{
   B f();
};

I do see the problem with the code above : A is virtual, thus no instance of A can be created, hence no instance of A can be returned.

Yet, concrete subclasses of A (e.g. B) will have to implement the function f, which will always be able to return an instance of themselve (e.g. instance of B), i.e. an instance of a subclass of A.

While the above is incorrect and does not compile, is there a way to get something similar valid ? Possibly, but not necessarily, of the like:

class A 
{
   virtual "a concrete sublclass of A" f()=0;
};

note: I prefer not to return a pointer or a reference, as I would prefer B not to have to manage an instance of itself as attribute.

note: if possible c++11, but curious to hear about newer versions as well

4 Answers

Your attempted solution risks object slicing. Copying a B as an A will probably not work the way you expect. In general, it's best to avoid value semantics when dealing with polymorphic types. Consider returning a std::unique_ptr<A> instead :

#include <memory>
class A
{
public:
   virtual std::unique_ptr<A> f()=0;
};

class B : public A
{
public:
   std::unique_ptr<A> f() override;
};

This requires C++11. It will behave the way you expect and the user won't have to manage the lifetime of the resulting object.

However, contrary to what was shown in the original code, B::foo() won't give you access to the full interface of a B. It's not clear to me if this is required or not. If it is, you will need an extra layer. For example, define a g() that returns std::unique_ptr<B> which f() calls :

class B : public A
{
public:
   std::unique_ptr<A> f() override { return g(); }
   std::unique_ptr<B> g();
};

It looks like you're trying to write a factory or clone function of sorts. This is commonly done using std::unique_ptr to cleanly pass ownership of the created object to the caller:

class A
{
   virtual std::unique_ptr<A> f() = 0;
};

class B : public A
{
   std::unique_ptr<A> f() override;
};

Demo

The only downside is that you cannot have B::f return a std::unique_ptr<B> as that's not covariant with std::unique_ptr<A> (even though it implicitly converts to it).

note: if possible c++11, but curious to hear about newer versions as well

No. that is not possible. You can return a covariant type in a derived class though.

If the return type in the base classs is A&, it is ok to return B& in B.
If the return type in the base classs is A*, it is ok to return B* in B.

class A
{
   virtual A& f()=0;
   virtual A* g()=0;
};

class B : public A
{
   B& f();
   B* g()=0;
};

Write something like

class A
{
   virtual const A& f() const = 0;
};

class B : public A
{
   const B& f() const override { return *this; }
};

Instead of reference you may use pointers.

Related