473,473 Members | 1,541 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

inheritance and STL

I've been using STL for some time, but I have discovered an issue that
I'm sure has been resolved, but I'm not sure on the proper way to use STL
to solve this issue.

The issue is inheritance and the use of STL containers.

Consider a base class Fruit, with derived classes Orange, Banana and
Apple.

I want to create an STL container of "Fruits", which may be Orange,
Banana or Apple. I don't have any generic Fruit.

I create the container (lets say a deque) as follows:

deque<Fruit> theCrate;

In my application, I create anOrange, aBanana and anApple as follows:

Banana aBanana;
Orange anOrange;
Apple anApple;

Lets say that class Fruit has a virtual method "Eat". I declare a
virtual Eat for each derived class of Fruit (that is, for Banana, Apple
and Orange).

I add instances of Orange, Apple and Banana to my deque as follows:

theCrate.push_back (anOrange);
theCrate.push_back (aBanana);
theCrate.push_back (anApple);

if I perform the following code

for (deque<Fruit>::iterator pF = theCrate.begin ()
pF != theCrate.end ();
pF++)
pF->Eat ();

What I get is three executions of the method Fruit::Eat.
The fact that anOrange, aBanana and anApple are derived from Fruit, but
not a fruit, is lost on STL.

What is happening is that STL is enforcing using the Fruit contructor,
not the Orange, Banana or Apple constructors, and the nature of each
fruit is lost.

If I use the following container

deque<Fruit*> theCrate,

and store points to aBanana, anOrange and anApple, when I execute

(*pF)->Eat ();

I get executions of Banana::Eat, Orange::Eat and Apple::Eat.

Is there any way around this problem? I don't want to store pointers.

Regards,

Harvey

--
Harvey J Cohen, Ph. D

"The difference between fiction and reality is that fiction has to make
sense." - Tom Clancy
Jul 23 '05 #1
6 1674
Harvey J Cohen, Ph. D. wrote:
I've been using STL for some time, but I have discovered an issue that
I'm sure has been resolved, but I'm not sure on the proper way to use STL
to solve this issue.

The issue is inheritance and the use of STL containers.

Consider a base class Fruit, with derived classes Orange, Banana and
Apple.

I want to create an STL container of "Fruits", which may be Orange,
Banana or Apple. I don't have any generic Fruit.

I create the container (lets say a deque) as follows:

deque<Fruit> theCrate;

In my application, I create anOrange, aBanana and anApple as follows:

Banana aBanana;
Orange anOrange;
Apple anApple;

Lets say that class Fruit has a virtual method "Eat". I declare a
virtual Eat for each derived class of Fruit (that is, for Banana, Apple
and Orange).

I add instances of Orange, Apple and Banana to my deque as follows:

theCrate.push_back (anOrange);
theCrate.push_back (aBanana);
theCrate.push_back (anApple);

if I perform the following code

for (deque<Fruit>::iterator pF = theCrate.begin ()
pF != theCrate.end ();
pF++)
pF->Eat ();

What I get is three executions of the method Fruit::Eat.
The fact that anOrange, aBanana and anApple are derived from Fruit, but
not a fruit, is lost on STL.

What is happening is that STL is enforcing using the Fruit contructor,
not the Orange, Banana or Apple constructors, and the nature of each
fruit is lost.
As it must. An STL container "owns" its contained objects, which means
if you have a deque of Fruit objects, the container must allocate space
for each such object it holds. Given this, it should be clear that a
derived class object which may, in general, be larger than the base
class object cannot fit in the space allocated by the container.

The general consequence of this is "slicing" of the derived object when
the base object is constructed within the container, so despite your
best efforts, the container really is holding only a Fruit, not an Orange.

-Mark

If I use the following container

deque<Fruit*> theCrate,

and store points to aBanana, anOrange and anApple, when I execute

(*pF)->Eat ();

I get executions of Banana::Eat, Orange::Eat and Apple::Eat.

Is there any way around this problem? I don't want to store pointers.

Regards,

Harvey

Jul 23 '05 #2
> Is there any way around this problem? I don't want to store pointers.

From what I've read, the answer to this question is, "No."

- JFA1
Jul 23 '05 #3
"Harvey J Cohen, Ph. D."

deque<Fruit> theCrate; deque<Fruit*> theCrate, and store points to aBanana, anOrange and anApple, when I execute

(*pF)->Eat ();

I get executions of Banana::Eat, Orange::Eat and Apple::Eat.

Is there any way around this problem? I don't want to store pointers.


There is no way as the others have pointed out. Are you are worried about
memory issues, such as when you copy theCrate1 into theCrate2 you need to
make a copy of the underlying Fruit or increment a reference count otherwise
you have two pointers pointing to the same object and when you delete both
your program crahses, or when you delete theCrate then delete the pointed-to
objects?

If so, then consider using a reference counted pointer class, for example:

deque<boost::shared_ptr<Fruit> > theCrate;

You can also write your own smart pointer class whose copy constructor calls
the clone member function on its underlying pointer.

// requied traits: T::clone()
template <class T>
class deep_ptr {
public:
deep_ptr(T * ptr = NULL) : d_ptr(ptr) { }
deep_ptr(const deep_ptr& that) : d_ptr(that.d_ptr->clone()) { }
deep_ptr& operator=(const deep_ptr&);
~deep_ptr() { delete d_ptr; }
T* operator->() const { return d_ptr; }
T& operator*() const { return *d_ptr; }
private:
T * d_ptr;
};

It seems like a useful class, and I wonder if boost has something like it.
Reference counting mechanisms like shared_ptr may cause some performance
degradation in multi-threaded environments, where we have to use (platform
dependent) mutex locks to prevent two threads from changing the same memory
at once.
Jul 23 '05 #4
"Harvey J Cohen, Ph. D." <Ha***************************@adelpREALLYNOSPAMhi a.net> wrote in message news:<Xn*********************************@216.196. 97.142>...
I want to create an STL container of "Fruits", which may be Orange,
Banana or Apple. I don't have any generic Fruit.

I create the container (lets say a deque) as follows:

deque<Fruit> theCrate;

In my application, I create anOrange, aBanana and anApple as follows:

Banana aBanana;
Orange anOrange;
Apple anApple;

Lets say that class Fruit has a virtual method "Eat". I declare a
virtual Eat for each derived class of Fruit (that is, for Banana, Apple
and Orange).

I add instances of Orange, Apple and Banana to my deque as follows:

theCrate.push_back (anOrange);
theCrate.push_back (aBanana);
theCrate.push_back (anApple);

What you can do is use the pimple idiom to create a fruit handle that
has value semantics:

class fruit_handle
{
std::auto_ptr<fruit> pimpl;
public:
fruit_handle(const fruit_handle& X) : pimpl(X.pimple->clone()) {}
template<typename T> fruit_handle(const T& X) : pimple(X.clone()) {}
};

Clearly, your base class must have a virtual clone function and, of
corse, a virtual destructor.

struct fruit
{
virtual ~fruit = 0;
virtual void clone()const =0;
virtual void Eat() =0;
//any other virtual method you like
};
Now you define the container

std::deque<fruit_handle> theCrate;

and you can do

theCrate.push_back (anOrange);
theCrate.push_back (aBanana);
theCrate.push_back (anApple);

since fruit_handle now has value semantics, i.e., you can copy handles
around.

Andrea
Jul 23 '05 #5
On Wed, 30 Mar 2005 23:59:42 -0600, "Harvey J Cohen, Ph. D."
<Ha***************************@adelpREALLYNOSPAMhi a.net> wrote:
I've been using STL for some time, but I have discovered an issue that
I'm sure has been resolved, but I'm not sure on the proper way to use STL
to solve this issue.
The issue is inheritance and the use of STL containers.
Consider a base class Fruit, with derived classes Orange, Banana and
Apple.

I want to create an STL container of "Fruits", which may be Orange,
Banana or Apple. I don't have any generic Fruit.
I create the container (lets say a deque) as follows:

deque<Fruit> theCrate;

In my application, I create anOrange, aBanana and anApple as follows:
Banana aBanana;
Orange anOrange;
Apple anApple;

Lets say that class Fruit has a virtual method "Eat". I declare a
virtual Eat for each derived class of Fruit (that is, for Banana, Apple
and Orange).

I add instances of Orange, Apple and Banana to my deque as follows:

theCrate.push_back (anOrange);
theCrate.push_back (aBanana);
theCrate.push_back (anApple);
What you are doing here is called 'object slicing'
( http://c2.com/cgi/wiki?ObjectSlicing ).
if I perform the following code

for (deque<Fruit>::iterator pF = theCrate.begin ()
pF != theCrate.end ();
pF++)
pF->Eat ();

What I get is three executions of the method Fruit::Eat.
The fact that anOrange, aBanana and anApple are derived from Fruit, but
not a fruit, is lost on STL.

What is happening is that STL is enforcing using the Fruit contructor,
not the Orange, Banana or Apple constructors, and the nature of each
fruit is lost.

If I use the following container

deque<Fruit*> theCrate,

and store points to aBanana, anOrange and anApple, when I execute

(*pF)->Eat ();

I get executions of Banana::Eat, Orange::Eat and Apple::Eat.

Is there any way around this problem? I don't want to store pointers.


Yes and No. No, because you can't avoid pointers in polymorphic
situations. Yes, because you can avoid the hassle with pointers by
using a special container for pointers, e.g.
http://www.codeproject.com/vcpp/stl/ptr_vecto.asp .

Best regards,
Roland Pibinger
Jul 23 '05 #6
Harvey J Cohen, Ph. D. wrote:
[stl and derived classes, snip]
Consider a base class Fruit, with derived classes Orange, Banana and
Apple.


And don't forget: A container of child is not a child of container
of parent. You can't park your nuclear submarine in the motorcycle
parking lot. As somebody else suggested, you need to store some
kind of handle object that will deal with the specific kind of
fruit it is going to hold onto.
Socks

Jul 23 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: AIM | last post by:
Error in msvc in building inheritance.obj to build hello.pyd Hello, I am trying to build the boost 1.31.0 sample extension hello.cpp. I can not compile the file inheritance.cpp because the two...
2
by: Graham Banks | last post by:
Does using multiple inheritance introduce any more performance overhead than single inheritance?
4
by: JKop | last post by:
I'm starting to think that whenever you derive one class from another, that you should use virtual inheritance *all* the time, unless you have an explicit reason not to. I'm even thinking that...
5
by: Morgan Cheng | last post by:
It seems no pattern defined by GoF takes advantage of multiple inheritance. I am wondering if there is a situation where multiple inheritance is a necessary solution. When coding in C++, should...
10
by: davidrubin | last post by:
Structural inheritance (inheriting implementation) is equivalent to composition in that a particular method must either call 'Base::foo' or invoke 'base.foo'. Apparantly, The Literature tells us to...
14
by: Steve Jorgensen | last post by:
Recently, I tried and did a poor job explaining an idea I've had for handling a particular case of implementation inheritance that would be easy and obvious in a fully OOP language, but is not at...
22
by: Matthew Louden | last post by:
I want to know why C# doesnt support multiple inheritance? But why we can inherit multiple interfaces instead? I know this is the rule, but I dont understand why. Can anyone give me some concrete...
45
by: Ben Blank | last post by:
I'm writing a family of classes which all inherit most of their methods and code (including constructors) from a single base class. When attempting to instance one of the derived classes using...
60
by: Shawnk | last post by:
Some Sr. colleges and I have had an on going discussion relative to when and if C# will ever support 'true' multiple inheritance. Relevant to this, I wanted to query the C# community (the...
6
by: Bart Simpson | last post by:
I remember reading on parashift recently, that "Composition is for code reuse, inheritance is for flexibility" see (http://www.parashift.com/c++-faq-lite/smalltalk.html#faq-30.4) This confused...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.