7

Both clang 3.5.0 and g++ 4.9.0 compile the following code fine (with -std=c++11 -Wall -Wextra -pedantic-errors) and the program outputs true:

#include <iostream>

struct A
{
    virtual ~A() = default;
};

struct B
{
    virtual ~B() = default;
};

struct C : A, B
{
    virtual ~C() = default;
};

int main()
{
    C c;
    A* ap = &c;
    B* bp = dynamic_cast<B*>(ap);

    std::cout << std::boolalpha << (bp != nullptr) << std::endl;
}
Constructor
  • 7,273
  • 2
  • 24
  • 66
  • 1
    Is there a particular reason you suspect the behaviour you see may be wrong? (It's a valid question either way, but it would make a difference in what a good answer should focus on.) –  Oct 15 '14 at 14:16
  • @hvd I was almost sure that it was not possible. I don't know why. :) – Constructor Oct 15 '14 at 14:18
  • @hvd I mean I assumed that the output of the program should be `false`, not that use of `dynamic_cast` may be invalid in some cases, of course. – Constructor Oct 15 '14 at 14:27
  • Note that this won't link with [`libc++`](http://coliru.stacked-crooked.com/a/3dcadb2d30be777b). – David G Oct 15 '14 at 14:36
  • Just to add some information regarding this scenario. In case "ap" was a pointer to some class not related to the hierarchy of B, this dynamic_cast would return null and you must check if "bp" is NULL before dereferencing it. Another way to do this is by using a reference with dynamic_cast: `B* bp = nullptr; try{ bp = &(dynamic_cast(*ap)); } catch (...) { std::cout << "exception" << std::endl; }` – fhsilva Oct 15 '14 at 16:07
  • @0x499602D2 There's some kind of ABI issue with clang on Coliru, it often [needs -lsupc++ for runtime support](http://coliru.stacked-crooked.com/a/248d924cf162ba86). – Casey Oct 15 '14 at 18:08
  • @fhsilva Yes, I know it. – Constructor Oct 16 '14 at 18:55

2 Answers2

8

Yes. That's sometimes known as cross-casting, and will succeed if they are both base sub-objects of the same derived object, as they are here.

dynamic_cast is necessary, since the conversion needs the run-time information that both are part of a C object. To statically cast, you'd have to explicitly convert to C* first.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
7

Yes, as per §5.2.7 [expr.dynamic.cast], for dynamic_cast<T>(v) (emphasis mine):

If C is the class type to which T points or refers, the run-time check logically executes as follows:

— If, in the most derived object pointed (referred) to by v, v points (refers) to a public base class subobject of a C object, and if only one object of type C is derived from the subobject pointed (referred) to by v the result points (refers) to that C object.

Otherwise, if v points (refers) to a public base class subobject of the most derived object, and the type of the most derived object has a base class, of type C, that is unambiguous and public, the result points (refers) to the C subobject of the most derived object.

— Otherwise, the run-time check fails.

In your case, v refers to a most derived object that is an instance of your C, but the static type of v is a pointer to the public base class A. The C base class mentioned in the quotation is your B.

chris
  • 60,560
  • 13
  • 143
  • 205
  • Also relevant to someone who might just be wondering it: 11.2.2 - `In the absence of an access-specifier for a base class, public is assumed when the derived class is defined with the class-key struct and private is assumed when the class is defined with the class-key class.` – Marco A. Oct 15 '14 at 14:27
  • @MarcoA., I guess that would be good to note, yes. Thank you. – chris Oct 15 '14 at 14:27
  • @MarcoA. How does your quote relate to the question or answer? – Constructor Oct 15 '14 at 14:32
  • @Constructor Just noting that if you used `class` instead of `struct` the above won't work – Marco A. Oct 15 '14 at 14:34
  • Note that this won't link with [`libc++`](http://coliru.stacked-crooked.com/a/3dcadb2d30be777b). – David G Oct 15 '14 at 14:36
  • @MarcoA. Ah, sorry. I usually use `struct`s in my questions and answers thanks to this wonderful simplification. – Constructor Oct 15 '14 at 14:36
  • @0x499602D2 It is interesting. Why? – Constructor Oct 15 '14 at 14:37
  • 1
    @Constructor Seems to be a problem with the libc++ abi. [Here's a related post.](http://stackoverflow.com/questions/16271976/undefined-reference-to-dynamic-cast-using-libc-on-ubuntu) – David G Oct 15 '14 at 14:39