C++ inheritance downcasting
Asked Answered
C

7

29

I have my base class as follows:

class point    //concrete class
{
 ...    //implementation
}

class subpoint : public point  //concrete class
{
...     //implementation
}

How do I cast from a point object to a subpoint object? I have tried all three of the following:

point a;
subpoint* b = dynamic_cast<subpoint*>(&a);
subpoint* b = (subpoint*)a;
subpoint b = (subpoint)a;

What is wrong with these casts?

Cranial answered 7/8, 2012 at 22:27 Comment(0)
D
45

How do I cast from a point object to a subpoint object?

You can't; unless either point has a conversion operator, or subpoint has a conversion constructor, in which case the object types can be converted with no need for a cast.

You could cast from a point reference (or pointer) to a subpoint reference (or pointer), if the referred object were actually of type subpoint:

subpoint s;

point & a = s;
subpoint & b1 = static_cast<subpoint&>(a);
subpoint & b2 = dynamic_cast<subpoint&>(a);

The first (static_cast) is more dangerous; there is no check that the conversion is valid, so if a doesn't refer to a subpoint, then using b1 will have undefined behaviour.

The second (dynamic_cast) is safer, but will only work if point is polymorphic (that is, if it has a virtual function). If a refers to an object of incompatible type, then it will throw an exception.

Deputy answered 7/8, 2012 at 22:51 Comment(3)
The object that will be casted actually is of type subpoint, it is just in an array of points.Cranial
static_cast could also result in unaligned objects. I ran into the issue on 32-bit ARM. I cast to the derived object, and then called a function present only in the derived object. UBsan produced a bunch of findings. I had to switch to dynamic_cast to squash them.Dubious
@jww, If I do not have virtual function, do I still have to worry about unaligned objects since I will not be able to use dynamic_cast at all?Irreformable
P
11

The purpose of a dynamic cast is to "check at run time if an object is of a certain type in the hierarchy". So now let's look at what you have:

  1. You have a point object. Not a subpoint.
  2. You're asking a dynamic cast if the object is a subpoint. It's not.
  3. Because its not a subpoint, dynamic_cast fails - its way of telling you that the object is not the type you're trying to cast it to.

By contrast, this would have worked:

subpoint c;
point *a = &c;
subpoint* b = dynamic_cast<subpoint*>(&a);
subpoint* b = (subpoint*)a;
Periwig answered 8/8, 2012 at 3:15 Comment(1)
that's the correct answer! if base is constructed on it's own then it can't be downcasted. ie. dynamic_cast will fail!Boanerges
D
6

Overall, this will not work because point is not a subpoint; only the reverse is true. However, there are other issues as well.

In order:


subpoint* b = dynamic_cast<subpoint*>(&a);

dynamic_cast only works on polymorphic types, i.e., types that declare at least one virtual function. My guess is that point has no virtual functions, which means it cannot be used with dynamic_cast.


subpoint* b = (subpoint*)a;

For this cast to work, point needs to declare a conversion operator to subpoint *, e.g., point::operator subpoint *().


subpoint b = (subpoint)a;

For this cast to work, point needs to declare a conversion operator to subpoint or subpoint needs to have a constructor that takes a parameter convertable from point.

Draco answered 7/8, 2012 at 22:36 Comment(0)
V
5

For the first example, dynamic_cast only works if there's at least one virtual method in the base class. And if the object isn't actually of the type you're trying to cast, it will result in NULL.

For the second example you need &a instead of a, but once you've fixed that you'll get undefined behavior because the object type is wrong.

The third example requires an operator subpoint() method in point to do a conversion while creating a copy.

Valued answered 7/8, 2012 at 22:38 Comment(1)
@MooingDuck, define "won't work"? It should return a NULL pointer, which may not be the expected result but it does compile and do something useful.Valued
R
1

a can't be made into a subpoint. that implementation isn't there.

Remora answered 7/8, 2012 at 22:28 Comment(0)
S
1

What is wrong with these casts?

The fact that you attempt to do them. A point is not a subpoint, I'd be surprised if it worked.

Symbiosis answered 7/8, 2012 at 22:28 Comment(0)
G
0

I know this is an old (nearly ten year old) question, but I ran into this same issue recently.

I'm not sure what the original poster's intention was, but there can be a case where you want to have a base class that you derive subclasses from, and these subclasses only provide methods which act differently from each other, and utilize the same base data, without adding any of their own data elements.

If you need to do this (for some reason), and want to be able to downcast a base/parent object to a child that was originally instantiated as a parent, then you do not want to use virtual methods, as they will work against you, and you will always be forced to use the virtual methods of the class that was instantiated, and no amount of casting will call the child methods.

So, this can certainly be done. It's just not considered to be "safe". Also, you cannot use dynamic_cast here, it must be a static_cast.

Graben answered 14/1, 2022 at 1:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.