How do I make an abstract class properly return a concrete instance of another abstract class?

时间秒杀一切 提交于 2020-01-17 12:52:11

问题


I recently reworked one of my own libraries to try out separating interface from implementation. I am having on final issue with a class that is meant to return an instance of another class.

In the interface definition, I do something like

struct IFoo
{
    virtual const IBar& getBar() = 0;
}

and then in the concrete Foo getBar looks like

const IBar& Foo::getBar()
{
    Bar ret = Bar();
    return ret;
}

The problem is ret gets deleted as soon as getBar is done, causing a big crash when the copy constructor tries to use Bar like so

const Bar myBar = myFoo.getBar();

I have been reading various things, and I know returning by reference is frowned upon, but I do not see any other way (I do not want to return Bar* because I do not want to have to manually delete the return value).

What is the proper way (if any way exists) for an abstract class to return an instance of a concrete class derived from another abstract class?

Note I did see this solution: returning an abstract class from a function but I do not want to make the return value static and loose thread safety.


回答1:


Use smart pointers. These are pointers deleted when not used anymore (see for example http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/smart_ptr.htm).




回答2:


You can also return the object by value.

Some compilers provide the Return value optimization which optimize away the copy when returning an object.

Edit:
Sorry. I skimmed through the question and somehow missed the fact that inheritance is involved. Assuming that getBar() can return various kind of IBar returning an IBar pointer makes a lot of sense.

By returning a pointer to base the concrete object is kept intact. The slicing problem is avoided and the original vtbl pointer is available to make virtual function calls. Also (as you noted in your comment) returning an instance of an abstract class is just impossible.

Instead of returning a raw pointer I suggest you return a shared_ptr<IBar> to simplify memory management.

const shared_ptr<IBar> Foo::getBar()
{
    shared_ptr<IBar> ret(new Bar());
    return ret;
}

Then use it this way:

shared_ptr<IBar> pIBar(foo.getBar());
pIBar->myVirtualFunction();

shared_ptr is the most commonly used smart pointer type in C++0x. If you have a sufficiently recent compiler it will be in the std namespace. Older compiler may have it in the tr1 namespace and it's also part of boost.




回答3:


You're returning a reference to a local variable. As soon as the function returns the reference, the stack gets popped and that Bar object ceases to exist.

EDIT: I didn't read the whole thing. You'll probably need to use a smart pointer.

Actually, is there any reason why you need to return a base class reference? You could avoid any smart pointer messiness by returning an object of the concrete type itself, since C++ allows covariant return types.




回答4:


Since you want to transfer ownership of the returned object to the caller, the caller will have to destroy the object. In other words, returning IBar * is your best bet. If you are worried about having to manually call delete, you should look into using a smart pointer package, e.g. boost::shared_ptr.




回答5:


If you don't want to take care of deletion then you have to use SmartPointers. In C++ this is the only way to have object "deletes itself" when it is appropriated.

http://en.wikipedia.org/wiki/Smart_pointer




回答6:


The object that has been created on the stack will be destructed when your stack is removed. The stack is removed when the function exits.

Instead, try something like this:


struct Foo : public IFoo
{
  Bar m_Bar;
public:
  virtual const IBar& getBar() 
  { 
    return m_Bar;
  }
}


来源:https://stackoverflow.com/questions/3327307/how-do-i-make-an-abstract-class-properly-return-a-concrete-instance-of-another-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!