views:

214

answers:

3

The following code, prints out

Derived
Base
Base

But I need every Derived object put into User::items, call its own print function, but not the base class one. Can I achieve that without using pointers? If it is not possible, how should I write the function that deletes User::items one by one and frees memory, so that there should not be any memory leaks?

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

class Base{
public:
  virtual void print(){ cout << "Base" << endl;}
};

class Derived: public Base{
public:
  void print(){ cout << "Derived" << endl;}
};

class User{
public:
  vector<Base> items;
  void add_item( Base& item ){
    item.print();
    items.push_back( item );
    items.back().print();
  }
};

void fill_items( User& u ){
  Derived d;
  u.add_item( d );
}

int main(){
  User u;
  fill_items( u );
  u.items[0].print();
}
+5  A: 

You need to use pointers, and you need to give your base class a virtual destructor. The destructor does not have to do anything, but it must exist. Your add function then looks like:

void add_item( Base * item ){
    item->print();
    items.push_back( item );
}

where items is a vector<Base *>. To destroy the items (assuming a virtual destructor):

for( int i = 0; i < items.size(); i++ ) {
    delete items[i];
}
items.clear();
anon
@Neil Should the virtual destructor exist just to make it virtual? So it will dynamically destroy the base and derived class objects?
Draco Ater
@Draco The destructor needs to be created and defined as virtual so that the destruction will follow the virtual function lookup mechanism when the object is deleted via a base class pointer. Destructors automatically "chain" from child to base, but you've got to get the child dtor called in the first place!
dash-tom-bang
In other words, for a non-virtual dtor, "delete items[i];" will only call the Base destructor and not the "actually derived" destructor. Adding 'virtual' makes the right function get looked up and called. (You only need the virtual tag on the base class destructor, btw, and you don't necessarily need explicit destructors for derived classes.)
dash-tom-bang
A: 

You need a virtual destructor for base to make sure objects of type Derived get destroyed properly when calling delete on a pointer of type Base.

class Base{
public:
  virtual void print(){ cout << "Base" << endl;}

  virtual ~Base( ) { }  // virtual destructor
};

Then you can use Boosts ptr_vector to store pointers to your objects that get deleted when the container gets destroyed.

Space_C0wb0y
It doesn't prevent memory leaks, it prevents undefined behaviour.
anon
Right. Added a tip about that.
Space_C0wb0y
Um, no you haven't.
anon
What is wrong/missing?
Space_C0wb0y
See my first comment. Undefined behaviour != memory leak. Also, it is not so helpful to suggest semantically complex Boost containers to someone learning C++. In order to use those containers correctly, one must understand the basic concepts of C++ first.
anon
Ok, I think I fixed it, thanks.
Space_C0wb0y
A: 

just explaining:

In order to understand what is going on, you may try to define class Base abstract (e.g. defining any method pure virtual). In this case I expect you'll see compiler errors. This way you'll recognize what vector actually does: it creates new instances of class Base by means of copy construction when you push_back( derived ). This is why you want to use pointers instead. Then vector works with your originally created objects of type Derived instead of own copies of type Base.

Stefan Hubert
yes, I knew that. That is called slicing. I just wanted to know is there any other opportunity except using pointers.
Draco Ater