tags:

views:

119

answers:

6

Hi,

I wish I could return an object of virtual base class so that I won't need to deal with the memory management(the idea of function programming also stimulate this pursuit). That means I am looking for some things like below:

class Car
{
  public:
     virtual int price() = 0 ;
     virtual string brand() = 0 ;
}

class Interface
{
  public:
     virtual Car giveMeACar() = 0 ;
     virtual vector<Car> listMeAllTheCars() = 0 ;
}

However, this won't even compile due to that Car is an abstract interface, with an error message :

invalid abstract return type for member function 'virtual Car giveMeACar() = 0 ; because the following virtual functions are pure within 'Car' : int price()
string brand() ;

So, does that means I have to revise the interface to something like below and manager the memory myself (delete the instance after using it) - ruling out the option of using smart pointer.

class Interface
{
  public:
     virtual Car* giveMeACar() = 0 ;
     virtual vector<Car*> listMeAllTheCars() = 0 ;
}

My question is : is this the only option I have when design an interface where every things(class) is abstract?

Returning an object of interface class is perfect valid in Java. C++ seems to be litter bit verbose and counter intuitive in this facet. More than often, I feel C++ is "pointer to object programming language" instead of a "object programming language" because without a pointer you can not get too much benefit of object programming.

+1  A: 

I think this might be of use.

Mike
For people reading the page, it's nice if there's some hint where the link leads...
Tony
+4  A: 

Your observations are correct, there is no easy way to do what you want to do. In C++ you can't return a Car by value because (among other things) the caller needs to allocate space for it.

Java isn't fundamentally different, it is just that its syntax can't express what you want to express - all types (except the primitive types) have an implicit '*' attached to them. And it has garbage collection, so you don't need to worry about memory management.

Keith Randall
Did you mean "its syntax CAN express what you want to express"?
pierr
No, I meant "can't". Java can't express the act of returning a class by value. All classes are implicitly passed by reference.Probably the closest Java to "Car x = giveMeACar();" in c++ is "Car x = (Car)giveMeACar().clone();" (if Car implements the clone method correctly).
Keith Randall
@keith, I am confused. Java should always pass by value. http://stackoverflow.com/questions/40480/is-java-pass-by-reference
pierr
Java only passes primitive types and "references" by value. The objects themselves are passed by reference. See the second code snippet of the top answer in your citation.
Keith Randall
+1  A: 

The other option is to use a template:

template<class CarClass>
class Interface {
    virtual CarClass giveMeACar() = 0;
    virtual vector<CarClass> listMeAllTheCars() = 0;
}
bbadour
+3  A: 

Return a std::auto_ptr< Car >. It puts the object on the heap like a pointer, but deletes it when it goes out of scope like a stack variable.

Variations include boost::unique_ptr and C++0x std::unique_ptr, which supercedes auto_ptr.

The vector<Car> cannot be replaced by vector< auto_ptr< Car > > because auto_ptr is incompatible with containers. You need to use unique_ptr for that.

Potatoswatter
And for concision, typeability and a single point of maintenance to switch between these pointer types (if later necessary for performance etc), you might want to create a typedef. This is a pretty common approach.
Tony
[Congratulations!](http://stackoverflow.com/badges/49/c?userid=153285)
James McNellis
A: 

Other posts in response to your query perfectly answer your query. However, I just had a few observations which you may consider

First observation:

Avoid exposing details about implementation to the external world.

This is with respect to the return type of

virtual vector<Car> listMeAllTheCars() = 0 ;.

Why should the users of class know if you are using vector or list or something else? Check out the Iterator Design Pattern from GOF. C++ has a good support for iterators.

Second observation:

Your requirement seems to mimic the need for Factory Method design pattern especially when I look at

virtual Car giveMeACar() = 0 ;

You may want to look at the Factory method Design Pattern

Third observation:

However the presence of both of these functions in a single interface, looks little out of place to me. You may want to consider the design again. Stick to Single Responsibility Principle.

Chubsdad
+4  A: 

In Java, "returning and object" is actually semantically equivalent to returning a pointer to the object in C++, you are trying to return an object by value, which makes a copy of it. You can't make a copy of an abstract object.

So, while C++ may be more verbose, it supports different semantics for passing parameters and returning values, which Java doesn't support (return by value, pass by reference).

With that said, you should return by smart pointer, which does memory management for you. Others have pointed out auto_ptr with ownership transfer semantics, but you can also use boost::shared_ptr, in case you use custom memory allocation internally (e.g. a pool), shared_ptr's custom deleter feature will help you hide deallocation details from the user of the interface. It can also be used in STL containers (unlike auto_ptr).

class Car
{
public:
    typedef boost::shared_ptr<Car> Ptr;
    virtual int price() = 0 ;
    virtual string brand() = 0 ;
};

class Interface
{
public:
    virtual Car::Ptr giveMeACar() = 0 ;
    virtual vector<Car::Ptr> listMeAllTheCars() = 0 ;
}
Alex B
I love the syntax after introducing boost. However, for an embedded project, the task of cross compiling the boost and unexpected issue involving always keeps me away from using it...
pierr
@pierr, yeah boost is a bit of a pig, but `shared_ptr` hass header-only implementation, you don't need to link to any boost libraries. You can also check if your compiler supports `std::tr1::shared_ptr` (GCC 4+, MSVC 2008 with feature pack), then you don't need boost at all.
Alex B
Luckily, my cross compiler support std::tr1::shared_ptr
pierr