should always return a pointer to class in interface design?
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 eve开发者_JS百科ry 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.
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 ;
}
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.
The other option is to use a template:
template<class CarClass>
class Interface {
virtual CarClass giveMeACar() = 0;
virtual vector<CarClass> listMeAllTheCars() = 0;
}
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.
I think this might be of use.
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.
Alex B statement is correct, but to give an old question a modern solution(C++11) you should return a std::unique_ptr. This passes ownership of the car to the caller and the car will be automatically deleted when the caller goes out of scope
#include <memory>
class Car
{
public:
virtual int price() = 0 ;
virtual string brand() = 0 ;
};
class Interface
{
public:
virtual std::uniqe_ptr<Car> giveMeACar() = 0 ;
virtual vector<std::uniqe_ptr<Car>> listMeAllTheCars() = 0;
}
精彩评论