Reputation: 1575
Lets say I have class A and it has a subclass B.
class A
{
public:
A(){};
}
class B : public A
{
public:
B(int value){ foo = value };
int foo;
}
B is a subclass of A with an int foo.
Okay now lets say I do the following:
std::vector<A> mylist;
B myB(5); //Create a new instance of class B
mylist.push_back(myB); //Add b to my vector of A.
Now I want to access an element of mylist and type cast it to type B and retrieve 'foo'. Is the following legal?
B *instance = (B *)&mylist[0];
I've tried doing this in my project but if I were to print out the value of foo it would be incorrect:
std::cout<<instance->foo<<std::endl; // This does not give me 5. It gives me a garbage number.
The problems stems from the fact that I don't know the proper way to cast non-pointers in C++.
Upvotes: 3
Views: 3717
Reputation: 141554
When you write mylist.push_back(myB)
, a slice occurs. The mylist
stores A
objects. So what happens is that your B
is converted to an A
, losing all of the things that are in B
and not A
. Just the A
is stored. You cannot retrieve the lost pieces.
It is the same as doing:
B myB(5);
A a(myB);
In order to have polymorphic behaviour, you need to make A
be a polymorphic class, and also refer to the objects by pointers, i.e. A *
.
So you need to add at least one virtual function to A
(virtual destructor would be a good idea), and have your vector store pointers. For example:
std::vector< A* > mylist;
mylist.push_back( new myB(5) );
B *instance = dynamic_cast<B *>(mylist[0]);
Now, this code is OK but you have to be very careful about deleting memory you new'd. To solve that for you there is shared_ptr
which is a ref-counted pointer. I made the following test case which seems to work (disclaimer - I'm not an expert in polymorphism with smart pointers, so I hope there is not a stealthy error here)
#include <iostream>
#include <memory>
#include <vector>
class A
{
public:
A(){};
virtual ~A() {}
};
class B : public A
{
public:
B(int value): foo(value) {}
int foo;
~B() { std::cout << "Destructor B(" << foo << ")" << std::endl; }
};
int main()
{
std::vector< std::shared_ptr<A> > mylist;
// Test the polymorphic behaviour
// mylist.push_back( std::make_shared<A>() );
// create directly into container
mylist.push_back( std::make_shared<B>(5) );
// via pointer
B *temp_b = new B(6);
mylist.push_back( std::shared_ptr<B>(temp_b) );
std::shared_ptr<B> instance = std::dynamic_pointer_cast<B>( mylist[0] );
if ( !instance )
std::cout << "Item was not a B" << std::endl;
else
std::cout << instance->foo << std::endl;
}
Upvotes: 4
Reputation: 53155
This is a typical example of slicing issues in C++.
You should store pointer in the vector to easily avoid them. If you do not wanna to deal with raw pointers, use smart pointers.
Upvotes: 2