Arthur O'Dwyer wrote:
> That's an upcast, not a downcast.
Sorry for my confused post yesterday. I got muddled while trying to map your
cats onto my already-half-forgotten original problem.
Here is a longer example that is closer to the code I was originally struggling with:
[...]
struct V { virtual ~V() = default; };
struct D { void foo() { std::cout << "foo"; } };
D here isn't a polymorphic type at all, so you can't use `dynamic_cast` with it. (Except in the special case
[expr.dynamic.cast]/4 where it's just a wacky spelling for `static_cast`).
You can check for that situation with `std::is_polymorphic_v`, and/or by using the `downcast` template I posted abovethread, which explicitly tests that we're doing a downcast.
foo("inherited CV", static_cast<CV&>(inherited)); // Unexpectedly calls D::foo.
foo("inherited DV", static_cast<DV&>(inherited)); // Calls D::foo.
FWIW, this example was initially confusing because you said "unexpectedly calls D::foo," and there's literally only one `foo` in the whole program (which is of course `D::foo`).
If you wanted some other `foo` to be called, wouldn't you have to provide it?
But then I realized that you meant "D::foo is called because dynamic_cast unexpectedly returns non-null,"
and that's because `dynamic_cast` unexpectedly doesn't behave like `downcast`,
and that's because... you didn't write `downcast`.
But if you do write `downcast`, I think everything works fine, right?
The consequence is that a class designer needs to consider how his class might
be inherited from (or, make it 'final').
Well, yes. Almost every class (certainly every business-logic class) is either:
- a non-polymorphic value-semantic type,
- a polymorphic abstract base class ("interface"), or
- a polymorphic leaf class ("implementation").
The type author should always know which of those things he's writing.
Only base classes should ever be inherited-from. You can enforce this (with `final`), although in practice usually I think that's overkill.
That's mostly irrelevant to this thread. But what is relevant is that `dynamic_cast` should be used only with polymorphic types!
–Arthur