Reputation: 9330
I have the following case in C++:
Abstract1
and Abstract2
. They are unrelated.Foo
deriving from both Abstract1
and Abstract2
I am in a compilation unit where I have no information about class Foo
(no declaration, no definition). Only Abstract1
and Abstract2
are known.
(Actually, Foo is even defined in a DLL)
Will dynamic_cast allow casting from Abstract1*
to Abstract2*
? Is this a standard?
Upvotes: 10
Views: 974
Reputation: 61009
What you describe is a so-called cross-cast. For dynamic_cast<T>(v)
, the standard specifies in [expr.dynamic.cast]/8
If
C
is the class type to whichT
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 aC
object [..]Otherwise, if
v
points (refers) to apublic
base class subobject of the most derived object, and the type of the most derived object has a base class, of typeC
, that is unambiguous andpublic
, the result points (refers) to theC
subobject of the most derived object.
That will work even with no information about Foo
's existence in the translation unit that contains the cast.
You should check out this question too.
Upvotes: 6
Reputation: 8406
Yes it will work.
dynamic_cast
is based on RTTI. The information provided by RTTI here is enough to determine the actual dynamic type of the pointed to object. By definition, RTTI is a run time notion, as is the dynamic type of the pointed to object (the fact that Foo's definition is not available in a compilation unit where said cast is written is a compile time notion, with no relevance here).
A possible implementation of dynamic_cast
is to look up a special member at the beginning of the object's memory layout (or it could be stored along the v-table). This structure could contain a value, which identifies the dynamic type of the object.
Somewhere, the compiler would have generated a static table, replicating all the information about your program inheritance diagram.
At run time, the cast would extract the type identifier of your instance, and check it against the static table. If this identifier refers to a type deriving from Abstract2, the cast is meaningful (and the code can return a pointer correctly offset to the Abstract2
interface of your object).
Even this naïve implementation never requires the knowledge of Foo
in the compilation unit where the
cast is written.
Upvotes: 4
Reputation: 30156
For this code:
void func(Abstract1* a1)
{
Abstract2* a2 = dynamic_cast<Abstract2*>(a1);
...
}
You're asking:
If a1
is pointing to a Foo
object, will the dynamic-cast return a valid object pointer?
The answer is yes:
a1
as the V-Table of class Foo
.class Foo
inherits from class Abstract2
, the dynamic-cast will return a valid pointer.Upvotes: 2
Reputation: 385405
Well, you could simply have tried it!
#include <cassert>
struct IBase1
{
virtual void foo() = 0;
virtual ~IBase1() {}
};
struct IBase2
{
virtual void bar() = 0;
virtual ~IBase2() {}
};
struct Derived : IBase1, IBase2
{
void foo() {}
void bar() {}
};
int main()
{
Derived d;
IBase1* ptr = &d;
assert(dynamic_cast<IBase2*>(ptr));
assert(dynamic_cast<Derived*>(ptr));
}
// Compiles successfully
And here's the proof:
[C++11: 5.2.7/8]:
IfC
is the class type to whichT
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 apublic
base class subobject of aC
object, and if only one object of typeC
is derived from the subobject pointed (referred) to byv
the result points (refers) to thatC
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 typeC
, that is unambiguous andpublic
, the result points (refers) to theC
subobject of the most derived object.Otherwise, the run-time check fails.
Colloquially, we call this cross-casting.
There is no requirement stipulated by the language that the most derived object's type be known about in the "current" translation unit; it's up to the implementation to make that work and, in the common "virtual tables" model, indeed it does.
Upvotes: 1