Dynamic_cast<pointer>

Hi all,

This is our base class called, Shape:

1
2
3
4
5
6
7
8
9
class Shape {
public:
virtual Point center() const = 0; // pure virtual
virtual void move(Point to) = 0;
virtual void draw() const = 0; // draw on current "Canvas"
virtual void rotate(int angle) = 0;
virtual ~Shape() {} // destructor
// ...
};


And this Circle type is our first derived class: (A Triangle shape can also this way derive from our bass class)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Circle : public Shape {
public:
Circle(Point p, int rad); // constructor
Point center() const override { return x; }

void move(Point to) override { x = to; }

void draw() const override;
void rotate(int) override {} // nice simple algorithm

private:
Point x; // center
int r; // radius
};


This is our Smiley subclass:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Smiley : public Circle { // use the circle as the base for a face

public:
Smiley(Point p, int rad) : Circle{p,r}, mouth{nullptr} { }

~Smiley()
{
delete mouth;
for (auto p : eyes)
delete p;
}

void move(Point to) override;
void draw() const override;
void rotate(int) override;
void add_eye(Shape* s){ eyes.push_back(s); }
void set_mouth(Shape* s);
virtual void wink(int i); // wink eye number i
// ...

private:
vector<Shape*> eyes; // usually two eyes
Shape* mouth;
};


We use the function read_shape() to read a Shape from the user:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
enum class Kind { circle, triangle, smiley };

Shape* read_shape(istream& is) // read shape descriptions from input stream is
{
// ... read shape header from is and find its Kind k ...
switch (k) {

case Kind::circle:
// read circle data {Point,int} into p and r
return new Circle{p,r};

case Kind::triangle:
// read triangle data {Point,Point,Point} into p1, p2, and p3
return new Triangle{p1,p2,p3};

case Kind::smiley:
// read smiley data {Point,int,Shape,Shape,Shape} into p, r, e1, e2, and m
Smiley* ps = new Smiley{p,r};
ps−>add_eye(e1);
ps−>add_eye(e2);
ps−>set_mouth(m);
return ps;
  }
}


How can the above function is implemented? Something like this?
E.g., when the user inputs 3 Points (pairs of int-s), and then ctrl+z, we infer from the input that k = Triangle
When a Point and an int, => k = Circle
And when a Point, an int and three other shapes, like above, so k = Smiley

Right up to here?

Now this dynamic_cast<> is used:

1
2
3
4
5
6
7
Shape* ps {read_shape(cin)};
if (Smiley* p = dynamic_cast<Smiley*>(ps)) { // ... does ps point to a Smiley?
// ... a Smiley; use it
 } 
else {
// ... not a Smiley, try something else ...
}


Here the if-condition checks whether the shape returned by read_shape() matches the characteristics of a Smiley shape or not. If so, then we use it.

The question here is that, what is the difference between code written above and one without a dynamic_cast<>?

1
2
3
4
5
6
7
Shape* ps {read_shape(cin)};
if (Smiley* p = ps) { // ... does ps point to a Smiley?
// ... a Smiley; use it
 } 
else {
// ... not a Smiley, try something else ...
}


What is the benefit of that dynamic_cast<> here?

PS: Please use simple language; I'm not a C++ expert! :)
Last edited on
Your last snippet does not compile. If you want to convert a base class pointer to a derived class pointer you have to cast it.
Last edited on
So, to be clear by pedantic review, you know that read_shape must return a pointer to the base type, which is to say at that moment there's no way to be sure that such a shape is, in fact, a Smiley.

Under the hood there is RTTI information embedded within the instantiation. This is used at runtime to determine the layout of an instance, meaning that this information can tell that the Shape * is in fact a Smiley or not a Smiley.

The compiler will not permit (or shouldn't if it's a competent compiler) Smiley *p = read_shape(cin), because the types don't match.

The dynamic_cast operator will perform a runtime test on the shape, inspecting the RTTI information, to perform the cast. There are far more complex reasons for this, but the bottom line is that the cast returns a nullptr if the Shape being cast is not the destination type you're requesting.

A static cast or other reinterpretation (like a C style cast) doesn't take this into account, which can give you a pointer that is entirely invalid. It may not be clear in your current example, so imagine not just Smiley, but a Rectangle derived from Shape. If you used a static or reinterpreting cast on Shape to get a Smiley, but the Shape was actually a Rectangle, the result would be invalid and likely a crash.

The dynamic cast will "inform" you if this condition by returning a nullptr.

There's more to this when multiple inheritance gets involved. Dynamic cast has more to do there, but that can wait until you cover multiple inheritance. Just know, for now, it is even more important in more complex designs to use dynamic casting where required.
Thanks so much to both of you. I got everything for now.
frek wrote:
1
2
3
4
5
6
7
Shape* ps {read_shape(cin)};
if (Smiley* p = ps) { // ... does ps point to a Smiley?
// ... a Smiley; use it
 } 
else {
// ... not a Smiley, try something else ...
}


What does use a smiley mean? If using a smiley means calling one of the functions in the base class, there is no need for any casting. If this is true, then it looks to me like a classic misunderstanding of virtual polymorphism. If one is going to use a Shape of any type, then that function should be part of the interface.

For example, say you have a std::vector of pointer to different Shapes, and you want to perform the same action on all of them: the rotate function from the base class. Just call the rotate function on each one, the correct version of rotate will be called depending on which Shape it is.

Did you obtain this code from somewhere? If so, could you provide a link to it?
Last edited on
There a Smiley is used, I think, by a specific method of its own, which is overridden from the base class.

And yes, it's from the book tour of C++ section 4-5 Class Hierarchies.
"Overridden." How?
@frek

If you have a function that is overridden from from the base class and it is virtual, then just call the function as I mentioned above:

ReturnType ps->function(); // ps is pointer to Shape!


cplusplustutorial wrote:
One of the key features of class inheritance is that a pointer to a derived class is type-compatible with a pointer to its base class. Polymorphism is the art of taking advantage of this simple but powerful and versatile feature.


This is indeed a very powerful feature and it simplifies code a lot.

And yes, it's from the book tour of C++ section 4-5 Class Hierarchies.


Could you post all of the code for that, I am intrigued as to why there is a dynamic cast at all? Is that a book by Stroustrup? If so, he would have had a reason ......... :+)
Could you post all of the code for that, I am intrigued as to why there is a dynamic cast at all? Is that a book by Stroustrup? If so, he would have had a reason ......... :+)


While I don't have the book or the code, I do know the reason.

He's illustrating the concept of the cast, contriving a hypothetical situation where a cast is required, and how it works (or returns nullptr in the context of such objects).

It isn't a design recommendation.

When you think about it, as you have, the circumstances where we must cast is rare, to such a point that for an early instruction to 101 level students, you're in quite a squeeze to produce examples that look informed to those of us this side of graduation.
Last edited on
@TheIdeasMan

Yes, the book is of him and I will post some screenshots from other parts later.

Smiley has some specific functions of its own which differ from other subclasses', hence we firstly need to be sure the object returned by read_Shape is a Smiley to be able to properly use those functions.
Topic archived. No new replies allowed.