Okay you have a fundamental misunderstanding here.
Polymorphism allows you to access a
child object through a
parent pointer. It
does not allow you to transform a parent object to a child object.
You cannot
ever transform a variable from one type to another. It simply is not possible in C++. Once you define a variable as a certain type... it is that type forever (or at least until the variable goes out of scope).
(You can, however, convert one type to another by transferring it to a DIFFERENT variable... but that's not what you want to do here, so nevermind that -- I only mention it for completeness).
With that in mind... when you do this:
This creates a
Shape2D
object. A Shape2D object is not a Square object. It will
never be a Square object.
Now... inheritance forms an "is a" relationship between two classes. When you derive Square from Shape2D like you're doing, this implies a few things:
1) Square objects contain everything that Shape2D objects do
2) Square objects
may contain more that Shape2D objects, but cannot contain less.
3) Since Squares contain everything Shape2Ds do, Squares can be treated as if they were Shape2Ds. IE: a Square "is a" Shape2D.
4) The "is a" relationship only goes one way. A child is a parent, but a parent is not a child. An easy to visualize example of this is child class Poodle deriving from parent class Dog. All Poodles are also Dogs, but that doesn't mean all Dogs are Poodles.
In your example... all Squares are also Shape2Ds. But that does not mean that a Shape2D is a Square.
So understanding the "is a" relationship, and realizing that you can't transform the type of an object after it's declared... how can you "dynamically" create an object based on user input?
You're trying to do something like this, which is wrong:
1 2 3 4 5 6 7 8 9 10
|
Shape2D shape; // creating a Shape2D object
if( user_wants_a_square )
{
... code that treats 'shape' like a square...
}
else if( user_wants_a_cross )
{
... code that treats 'shape' like a cross...
}
|
This of course is wrong because you don't have a Square or a Cross. You only have a Shape2D. A Shape2D is neither a Square nor a Cross.
What you need to do in order to get this to work is to create the object
dynamically. The above code is simply creating a Shape2D all the time. We want to create a Square or a Cross depending on user input. We can do this with pointers and the
new
operator:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
Shape2D* ptr; // 'ptr' is a pointer (NOT an object). It is not a shape
// itself, but rather it "points to" a shape that exists somewhere else in memory.
if( user_wants_a_square )
{
Square* sq = new Square; // create a Square object dynamically with 'new'
// this is a little tricky, conceptually. 'new' creates an UNNAMED object that is a Square.
// 'sq' is just a pointer, it is not a Square itself.. it just "points to" this unnamed Square
// object that we've created.
// you can use the 'sq' pointer to initialize the unnamed square here
ptr = sq; // now that the unnamed square is initialized, we can assign 'ptr' so that it
// ALSO points to this unnamed square object.
// This is where inheritance and the "is a" relationship comes in. Even though we have
// a Square object and not a Shape2D object, we can still point to it with a Shape2D
// pointer because a Square "is a" Shape2D.
}
else if( user_wants_a_cross )
{
Cross* cr = new Cross; // create a cross dynamically
// .. initialize the cross here
ptr = cr;
}
// at this point, 'ptr' could be pointing to either a Square object or a Cross object.
// you could then add this pointer to an array, or push_back it into a vector... or
// however you want to keep track of it.
|
The last thing I'll mention is that to prevent memory leaks, anything you
new
must also be
delete
d. When you are done using all these objects, you have to go back and delete any one pointer that points to the unnamed object:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
Square* foo = new Square; // allocates an unnamed object. 'foo' points to it
delete foo; // deletes whatever object 'foo' points to. Since 'foo' points
// to our unnamed object, this correctly cleans up.
// another example:
Square* foo = new Square; // allocates an unnamed object. 'foo' points to it
Square* bar = foo; // now 'bar' also points to the unnamed object
delete bar; // since bar points to the unnamed object, this cleans it up correctly.
// however, now that it's been deleted, the unnamed object no longer exists...
// so foo and bar now point to nothing (they're bad pointers)
// at this stage... you do NOT want to delete foo, because foo does not point to
// a valid object, so there is nothing for it to delete.
// remember that you aren't deleting the pointer... you are deleting the object.
|
Hopefully that clarifies.