Search code examples
c++pointersabstract-classreturn-typederived-class

how to return an abstract class using c++


Been running into a snag while working in C++. I've tried several answers on SO, as well as other places (like: returning an abstract class from a function, and How do I make an abstract class properly return a concrete instance of another abstract class?), but I've still been having trouble-- these don't seem to completely fit...

I have an abstract class, a derived class:

class AbstractClass {
    virtual std::string virtMethod() = 0;
}

class Derived : public AbstractClass {
    std::string virtMethod();
}

Also, I a separate class which I'm trying to get a return type of the abstract class (of course, returning an instance of the derived class).

I've tried using pointer and reference:

AbstractClass* methodFromOtherClass() {
    if (somethingIsTrue) {
        Derived d = Derived();
        return &d;
    }

    SomeOtherDerived s = SomeOtherDerived();
    return &s;
}

Which, in Xcode, gives me the warning:

Address of stack memory associated with local variable 'd' returned

I tried creating a static Derived object and was unable to then destroy it in the method which calls my "methodFromOtherClass()."

I've also tried my hand at smart pointers (though someone may point out my obvious misuse of them):

std::unique_ptr<AbstractClass> methodFromOtherClass() {
    if (somethingIsTrue) {
        Derived d = Derived();
        return std::unique_ptr<AstractClass>(&d);
    }

    SomeOtherDerived s = SomeOtherDerived();
    return std::unique_ptr<AstractClass>(&s);
}

The above, perhaps unsurprisingly, gives me a segfault.

I'm used to being able to do this easily in Java... Any help would be appreciated. C++ isn't a very strong language for me at the moment, so it could be something very basic which I'm overlooking.


Solution

  • Your basic problem (as the warning told you) is that your function is returning the address of a local variable, and that local variable ceases to exist when the function returns.

    Your first version can be changed to

    AbstractClass* methodFromOtherClass()
    {
        if (somethingIsTrue) 
        {
            Derived *d = new Derived();
            return d;
        }
    
        SomeOtherDerived *s = new SomeOtherDerived();
        return s;
    }
    

    Note that this requires the caller to delete the returned pointer when done.

    The second version can be changed to

    std::unique_ptr<AbstractClass> methodFromOtherClass()
    {
        if (somethingIsTrue)
        {
            Derived *d = new Derived();
            return d;
        }
    
        SomeOtherDerived *s = new SomeOtherDerived();
        return s;
    }
    

    which releases the caller from the obligation of releasing the dynamically allocated object.

    In both cases, AbstractClass will need a virtual destructor, to avoid undefined behaviour when releasing the returned object.

    Your underlying problem is that you're thinking in terms of how Java works, and C++ works very differently from Java in this regard. Stop trying to learn C++ by analogy with Java - in cases like this, you will make more trouble for yourself than it is worth. From a C++ perspective, Java blends the concepts of pointers and references into one thing, so working with C++ pointers and references like you would in Java is a recipe for trouble in C++.