views:

116

answers:

5

I tried to add objects to the "content" vector, and use show() on all of them. But the objects that are children (A, B) of "Base" behave like they were of "Base" type, what is not my intention. As it seems, I tried to use virtual functions but it doesn't work.

I hope that the code will speak for itself.

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

class A : public Base {
    public:
        virtual void show() { cout << "A "; }
};

class B : public Base {
    public:
        virtual void show() { cout << "B"; }
};



vector<Base> content;

void add(Base &o) {
    content.push_back(o);
}

A test1;
B test2;

add(test1);
add(test2);

for (size_t i = 0; i < content.size(); i++) {
        collection[i].show(); // output is: Base Base instead of A B
}   

Thanks in advance.

A: 
vector<Base*> content; // <<

void add(Base *o) { // <<
    content.push_back(o);
}

A test1;
B test2;

add(&test1); // <<
add(&test2); // <<

for (size_t i = 0; i < content.size(); i++) {
        collection[i]->show(); // <<
}   
Y. Shoham
Code as an answer usually fails to portray much information. You need to explain it: what it solves, how it solves it, etc. Also, you're not mentioning `delete`. EDIT: Accepted; oh irony.
GMan
GMan: no `new`, no `delete`
swegi
Fair enough, but that's not how it will be used in real code anyway. It will use `new` and `delete`.
GMan
@swegi: But from looking at std::Vector<Base*> you can't tell that. So you may suspect that you should delete it. This is why good C++ abhores RAW pointers.
Martin York
+1  A: 

STL containers store value object. What you have here is called slicing.

Nikolai N Fetissov
+3  A: 

What you have is a vector of Base.
When you add somthing to a vector it is copied into the vector But only the baser part is being copied. Thus you will loose all the dertived information.

This is cooqually refered to as the slicing problem.

A simple solution is to store pointers in the vector.

Martin York
A better solution is to store smart pointers in the vector. :-)
Thomas Matthews
A: 

You have to use vector<Base*> because currently the objects that you pass in add will be copied into a new object of type Base.

Fozi
+2  A: 

As others have said, you're experiencing slicing. The vector stores a Base, and any derived information gets sliced away.

Alleviate this with pointers:

std::vector<Base*> v;
v.push_back(new A);
v.push_back(new B);

The problem now is with releasing your resources. Before the vector goes out of scope, you'll need to iterate through it and delete each element. An even worse problem is with exceptions.

If at any point during the life-time of the vector, if an exception is thrown, it will unwind the stack, at some point releasing all your pointers in the vector; one giant memory leak.

If you use a more dedicated container, you will avoid this problem. Either write one yourself (not recommended, of course), or use boost pointer containers.

GMan