This program runs without any exception. Can you please explain why the dynamic cast and static casts are successful? And how C++ manages to resolve the required virtual function?
class Shape
{
private :
string helperFunction();
public :
virtual void draw() = 0;
virtual void type();
};
void Shape::type()
{
cout << "Shape Type";
}
// ----------------------------------------------------------------------------
class Circle : public Shape
{
private:
string circlething;
public :
virtual void draw();
virtual void type();
void CircleFunction();
};
void Circle::draw()
{
cout <<"Circle Draw" << endl;
}
void Circle::type()
{
cout <<"Circle Type" << endl;
}
void Circle::CircleFunction()
{
circlething = "Circle Thing";
cout << circlething;
cout << "Circle Function" << endl;
}
class Square : public Shape
{
private :
string squarething;
public :
virtual void draw();
virtual void type();
void SquareFunction();
};
void Square::draw()
{
cout <<"Square Draw" << endl;
}
void Square::type()
{
cout <<"Square Type" << endl;
}
void Square::SquareFunction()
{
squarething = "Square Thing";
cout << squarething;
cout << "Square Function" << endl;
}
// ----------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
vector<Shape *> shapes;
Circle circle;
Square square;
shapes.push_back(&circle);
shapes.push_back(&square);
vector<Shape *>::const_iterator i;
for (i = shapes.begin(); i < shapes.end(); ++i)
{
cout << "\n*** Simple Type ***\n" << endl;
(*i)->type();
(*i)->draw();
cout << "---Static Cast Circle--" << endl;
Circle* circle = static_cast<Circle*>(*i);
circle->type();
circle->draw();
circle->CircleFunction();
cout << "---Static Cast Square--" << endl;
Square* square = static_cast<Square*>(*i);
square->type();
square->draw();
square->SquareFunction();
cout << "---Static Cast Circle to Shape --" << endl;
Shape* shape1 = static_cast<Shape*> (circle);
shape1->type();
shape1->draw();
cout << "--- Dynamic Cast Circle to Shape --" << endl;
Shape* shape2 = dynamic_cast<Shape*> (circle);
shape2->type();
shape2->draw();
cout << "--- Static Cast Square to Shape --" << endl;
Shape* shape3 = static_cast<Shape*> (square);
shape3->type();
shape3->draw();
cout << "--- Dynamic Cast Square to Shape --" << endl;
Shape* shape4 = dynamic_cast<Shape*> (square);
shape4->type();
shape4->draw();
}
int x;
cin >> x;
return 0;
}
Let's start with why it isn't throwing any exceptions, since it's pretty simple: dynamic_cast
throws an exception when you try to cast a reference type, and it fails. When you use dynamic_cast
on pointers, it will return a pointer if it succeeds, or a null pointer if it fails.
As for why you've never getting a failed cast, all your dynamic_cast
are up the hierarchy, to produce a Shape *
. Since all the objects in question are derived from Shape
, this will always succeed -- and in fact, that conversion can be done implicitly.
To demonstrate what dynamic_cast
is really intended to do, let's write some slightly different code:
#include <iostream>
#include <vector>
using namespace std;
class Shape {
public :
virtual void draw() = 0;
};
class Circle : public Shape
{
public :
virtual void draw() { cout << "Circle Draw\n"; }
void circlefunc() { cout << "circle func\n"; }
};
class Square : public Shape
{
public :
virtual void draw() { cout << "Square Draw\n"; }
void squarefunc() { cout << "Square Func\n"; }
};
int main() {
vector<Shape *> shapes;
Circle circle;
Square square;
shapes.push_back(&circle); // implicit conversion from Circle * to Shape *
shapes.push_back(&square); // implicit conversion from Square * to Shape *
Circle *c;
Square *s;
for (int i=0; i<shapes.size(); i++) {
shapes[i]->draw(); // draw polymorphically
if (c = dynamic_cast<Circle *>(shapes[i])) // try to cast to Circle *
c->circlefunc(); // if it worked, invoke circlefunc
else if (s = dynamic_cast<Square *>(shapes[i])) // likewise for square
s->squarefunc();
}
return 0;
}
This time we're using the dynamic_cast to get from Shape *
to Square *
or Circle *
. This will succeed if and only if the dynamic type of the pointee object is that type. Otherwise it'll produce a null pointer. If and only if we get a non-null pointer, we invoke the member function for that specific type.
To summarize: When you have a pointer/reference to a derived object, you can convert to a pointer/reference to the base class implicitly. You don't need dynamic_cast
(or any explicit cast at all) because this is always safe.
When you convert from pointer/reference to base to get a pointer/reference to derived, then you normally want to use a dynamic_cast
. This will succeed/fail based on whether the actual type of the pointee object (i.e., the dynamic type) is the desired target (or a base of it) or not. In this case, failure is signaled differently depending on whether you're working with pointers or references. For a reference, failure will throw an exception. For a pointer, failure will produce a null pointer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With