Search code examples
c++classfunctionvirtualabstract

Returning abstract datatypes in C++ without dangling pointers


Hallo,

I come from a C# background and don't have a lot of C++ experience. To produce clean code I try to separate implementation and interfaces and use inheritance when possible. And when I tried to apply typical C# concepts to C++ I ran into a problem that I've been unable to resolve so far. I assume that this is probably trivial for an experienced C++ programmer but it has been driving me crazy for quite a while.

First I declare a base class (it contains no logic at the moment but it will in the future)

class PropertyBase : public IProperty
{
};

Then I define an interface for the Properties

class IProperty
{
public:
    virtual ~IProperty() {};
    virtual PropertyBase    correct(const ICorrector &corrector) = 0;
    virtual PropertyBase    joinWith(const PropertyBase &partner, const IRecombinator &recombinator) = 0;
};

This is where the problem comes in: The compiler returns errors for the two virtual functions saying that it is not allowed to declare a function that returns an abstract class. Of course I don't want to return an object of the type PropertyBase. I want to declare other classes that inherit from PropertyBase that return an instance of themselves.

Now I've read that a possible way around it is to modify IProperty like this to return pointers:

class IProperty
{
public:
    virtual ~IProperty() {};
    virtual PropertyBase*   correct(const ICorrector &corrector) = 0;
    virtual PropertyBase*   joinWith(const PropertyBase &partner, const IRecombinator &recombinator) = 0;
};

However I would like to avoid this if possible to prevent memory leaks. It would be great if someone would have a better idea to deal with this problem.

Thank you very much


Solution

  • If you're afraid of memory leaks, switch to smart pointers. That has the additional benefit of being self-documenting wrt. ownership of the returned object.

    class IProperty
    {
    public:
        virtual ~IProperty() {};
        virtual std::unique_ptr<PropertyBase> correct(const ICorrector &) = 0;
        virtual std::unique_ptr<PropertyBase> joinWith(const PropertyBase &,
                                                       const IRecombinator &) = 0;
    };
    

    In your client code:

    std::unique_ptr<PropertyBase> pb(property.correct(corrector));
    // use pb and forget about it; smart pointers do their own cleanup
    

    Or, if you want reference counting on the object:

    std::shared_ptr<PropertyBase> pb(property.correct(corrector));
    

    See MSDN docs for unique_ptr, shared_ptr.