some casting questions

J

Jess

Hello,

It seems both static_cast and dynamic_cast can cast a base class
pointer/reference to a derived class pointer/reference. If so, is
there any difference between them?

In addition, if I have a derived class object and then upcast it to
its base class, which cast operator should I use? Is it static_cast,
or, can I simply cast it implicitly without any operator? Does this
upcasting remove the derived class portion of the object? If after
the upcasting, I'd like to downcast it again, is it still possible? I
think if the derived class portion of the object is removed by
upcasting, then it's impossible to downcast it again, but should be
possible otherwise.

Thanks,
Jess
 
R

Rolf Magnus

Jess said:
Hello,

It seems both static_cast and dynamic_cast can cast a base class
pointer/reference to a derived class pointer/reference. If so, is
there any difference between them?

Yes. dynamic_cast will do a runtime-check to see if the object is actually
of that type or one derived from it (presuming you are having a polymorphic
class hiererchy).
In addition, if I have a derived class object and then upcast it to
its base class, which cast operator should I use?

None. You don't need to cast. Derived-to-base conversions are done
implicitly.
Is it static_cast, or, can I simply cast it implicitly without any
operator?

There is no such thing as an "implicit cast".
Does this upcasting remove the derived class portion of the object?

If you really cast an object, yes. That's usually referred to as "slicing".
But usually, you cast pointers or references, in which case no change to
the object is done.
If after the upcasting, I'd like to downcast it again, is it still
possible?

Yes, if you did it on a pointer or reference to the object, you can cast up
and down as much as you want.
I think if the derived class portion of the object is removed
by upcasting, then it's impossible to downcast it again, but should be
possible otherwise.

Right.
 
R

Robert Bauck Hamar

Jess said:
Hello,

It seems both static_cast and dynamic_cast can cast a base class
pointer/reference to a derived class pointer/reference. If so, is
there any difference between them?

Yes. The dynamic_cast will fail if the object is not a derived class
pointer/reference:

class A { /* at least one virtual function ... */ };
class B : public A { /* ... */ };

....

A a;
B *b = dynamic_cast<B*>(&a); // b is NULL;
B &b = dynamic_cast<B&>(a); // Throws a std::bad_cast

while static_cast says: "I know this base pointer/reference _is_ referencing
a derived object, so just do it."
In addition, if I have a derived class object and then upcast it to
its base class, which cast operator should I use? Is it static_cast,
or, can I simply cast it implicitly without any operator?

You can simply cast it implicitly.
Does this upcasting remove the derived class portion of the object?

Yes, unless you are casting by reference or pointer. If you're casting an
object, a copy will be made using the base class' copy constructor:

B b;
A a = b; // Creates memory for A, and initializes bar with A::A(b).
If after the upcasting, I'd like to downcast it again, is it still
possible?

No. The rest of the object is sliced off.
I think if the derived class portion of the object is removed by
upcasting, then it's impossible to downcast it again, but should be
possible otherwise.

Yes.

B b;
A& a = b; // a references b, and a later downcast will be possible.
B& bb = static_cast<B&>(a); // OK
B& bbb = dynamic_cast<B&>(a); // OK, no exception.
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

Hello,

It seems both static_cast and dynamic_cast can cast a base class
pointer/reference to a derived class pointer/reference. If so, is
there any difference between them?

Dynamic cast will return 0 if the class you are casting is not of the
type you specified.
In addition, if I have a derived class object and then upcast it to
its base class, which cast operator should I use? Is it static_cast,
or, can I simply cast it implicitly without any operator?

You can use normal assignment, no cast needed.
Does this
upcasting remove the derived class portion of the object?

You should use pointers or references to base class, if you try to
assign an object of derived type to an object of base you will lose what
was added in the derived class.
If after
the upcasting, I'd like to downcast it again, is it still possible?

Yes, if you have a pointer to reference.
I think if the derived class portion of the object is removed by
upcasting, then it's impossible to downcast it again, but should be
possible otherwise.

Yes, an object of base-class can not be cast to an object of derived
type, but a pointer or reference to base-class can.
 
J

James Kanze

It seems both static_cast and dynamic_cast can cast a base class
pointer/reference to a derived class pointer/reference. If so, is
there any difference between them?

Several. The dynamic_cast does actual run-time type checking.
It will fail (return a null pointer or throw an exception) if
the actual object is not of the right type. In addition,
dynamic_cast can do many casts that aren't possible with
static_cast; roughly speaking, static_cast can only move up and
down in the inheritance lattice; dynamic_cast can move anywhere.
Also, static_cast won't work from base to derived if the
inheritance is virtual. Finally, dynamic_cast only works from
base to derived if the types are polymorphic; static_cast
doesn't have this restriction.

In general, when casting within an inheritance hierarchy, you'll
almost always want dynamic_cast. static_cast is generally only
used to or from void*, or with various scalar or class types
(although I tend to prefer either C styles casts or functional
style casts here).
In addition, if I have a derived class object and then upcast
it to its base class, which cast operator should I use? Is it
static_cast, or, can I simply cast it implicitly without any
operator?

It depends on the context. Most of the time, you won't use a
cast at all, since the conversion is implicit. If you want to
force it, for example (say when calling a template function, so
that the template instantiates for the base class, and not for
the derived), either static_cast or dynamic_cast are fine; they
both have exactly the same behavior in this case.
Does this upcasting remove the derived class portion of the
object?

If you actually cast the object. Most of the time, casting
will in fact involve pointers or references to the object.
If after the upcasting, I'd like to downcast it again, is it
still possible? I think if the derived class portion of the
object is removed by upcasting, then it's impossible to
downcast it again, but should be possible otherwise.

Think of a static_cast of a class type as calling a constructor;
that's what it does, always. So it will depend on what
constructors are available. For pointers, you can generally go
back and forth, with a few restrictions: static_cast allows
derived to base even with a virtual base class, but you can't
use static_cast in that case to go back.
 
J

Jess

Several. The dynamic_cast does actual run-time type checking.
It will fail (return a null pointer or throw an exception) if
the actual object is not of the right type. In addition,
dynamic_cast can do many casts that aren't possible with
static_cast; roughly speaking, static_cast can only move up and
down in the inheritance lattice; dynamic_cast can move anywhere.

Thanks! Where else could dynamic_cast move to? Do you mean it cast an
object to a completely unrelated class object?

Also, static_cast won't work from base to derived if the
inheritance is virtual.

What is "virtual" inheritance? Is it the same as having virtual
functions in a base class?
Finally, dynamic_cast only works from
base to derived if the types are polymorphic; static_cast
doesn't have this restriction.

What types are polymorphic? Are they the ones with virtual
functions? If I have two classes, A is the base class, B is A's
derived class, then if A has virtual functions, then both A and B are
polymorphic? Therefore, does it mean I can dynamic_cast from A to B
and B to A only if they have virtual functions?
In general, when casting within an inheritance hierarchy, you'll
almost always want dynamic_cast. static_cast is generally only
used to or from void*, or with various scalar or class types

Can you please elaborate? :)
(although I tend to prefer either C styles casts or functional
style casts here).


It depends on the context. Most of the time, you won't use a
cast at all, since the conversion is implicit. If you want to
force it, for example (say when calling a template function, so
that the template instantiates for the base class, and not for
the derived), either static_cast or dynamic_cast are fine; they
both have exactly the same behavior in this case.


If you actually cast the object. Most of the time, casting
will in fact involve pointers or references to the object.


Think of a static_cast of a class type as calling a constructor;
that's what it does, always.

Does dynamic_cast also involve calling a constructor?
So it will depend on what
constructors are available. For pointers, you can generally go
back and forth, with a few restrictions: static_cast allows
derived to base even with a virtual base class, but you can't
use static_cast in that case to go back.

Do you mean if A is base with virtual functions and B is derived class
of A, then I can use "static_cast<A*>" on a B*, but I can't
"static_cast<B*>" on an A* object even if the A* object is really
pointing to a B object?

Thanks,
Jess
 
J

James Kanze

Thanks! Where else could dynamic_cast move to? Do you mean it cast an
object to a completely unrelated class object?

Not to a completely unrelated class, but consider something
like:

VB
/ \
L R
\ /
MD

The legal static_casts here are MD->L, MD->R, MD->VB, L->MB, and
R->MD. You'll notice that they all go up and down. All 12 of
the possible casts in the hierarchy are legal for dynamic_cast,
including such things as L->R.
What is "virtual" inheritance? Is it the same as having virtual
functions in a base class?

No. The two use the same keyword, but that's about it.
Basically, for a base class B (like VB above), all of the
instances inherited virtually are shared; there is just one
instance. For example, the above hierarchy would be created by
something like:

class VB {} ;
class L : public virtual VB {} ;
class R : public virtual VB {} ;
class MD : public L, public R {} ;

In other words, because both L and R inherit virtually from VB,
they both share the same instance.
What types are polymorphic? Are they the ones with virtual
functions?

A type is polymorphic if and only if it is a class type with one
or more vitual functions, yes. It's the definition in the
standard.
If I have two classes, A is the base class, B is A's
derived class, then if A has virtual functions, then both A and B are
polymorphic?

Yes. Virtualness is inherited.
Therefore, does it mean I can dynamic_cast from A to B
and B to A only if they have virtual functions?

You can dynamic_cast from derived to base with or without
virtual functions. You can dynamic_cast from base to derived,
or elsewhere in the hierarchy, only from the point at which
there are virtual functions.
Can you please elaborate? :)

What is there to elaborate? Within an inheritance lattice,
practically, dynamic_cast covers all your needs. The base class
will have virtual functions, otherwise there is no point in
having a hierarchy, and dynamic_cast works everywhere. (Note
that if the base class doesn't have at least a virtual
destructor, you don't want pointers to it roaming about anyway.)

In some cases, you need to cast to and from void*, typically in
the case of C compatible callbacks. In such cases, you may
prefer static_cast, because there are no virtual functions. If
there are virtual functions, the problem is a bit more
complicated---you must 1) cast the pointer to the final type
(typically a base class), using either static_cast or
dynamic_cast, 2) cast this pointer to void*, using static_cast
(dynamic_cast has the wrong semantics!), and then, after
recovering the void* in the callback, cast it to the target type
using static_cast. The presence of a void* makes a difference,
the results of static_cast< void* >( p ) are not the same as
those of dynamic_cast< void* >( p ); if p is a Base*, the first
returns the address of the Base sub-object, converted to void*,
and the second the address of the complete object, converted to
void*.

And of course, unless you're casting pointers or references,
dynamic_cast isn't allowed at all. While my personal preference
is for something like "(unsigned long)i", "static_cast< unsigned
long >( i )" is also acceptable, and preferred by others.

[...]
Does dynamic_cast also involve calling a constructor?

dynamic_cast only works with pointers or references, which don't
have constructors.
Do you mean if A is base with virtual functions and B is derived class
of A, then I can use "static_cast<A*>" on a B*, but I can't
"static_cast<B*>" on an A* object even if the A* object is really
pointing to a B object?

If the inheritance is virtual, yes. Try it:

class A { public: virtual ~A() {} } ;
class B : public virtual A {} ;

int
main()
{
A* pA = new B ;
B* pB = static_cast< B* >( pA ) ;
return 0 ;
}

This shouldn't compile. Replace static_cast with dynamic_cast,
however, and there's no problem.
 
J

Jess

Not to a completely unrelated class, but consider something
like:

VB
/ \
L R
\ /
MD

The legal static_casts here are MD->L, MD->R, MD->VB, L->MB, and
R->MD. You'll notice that they all go up and down. All 12 of
the possible casts in the hierarchy are legal for dynamic_cast,
including such things as L->R.


No. The two use the same keyword, but that's about it.
Basically, for a base class B (like VB above), all of the
instances inherited virtually are shared; there is just one
instance. For example, the above hierarchy would be created by
something like:

class VB {} ;
class L : public virtual VB {} ;
class R : public virtual VB {} ;
class MD : public L, public R {} ;

In other words, because both L and R inherit virtually from VB,
they both share the same instance.

Thanks again! I haven't used virtual inheritance... What is it to
"share" the same instance? Does it mean that if I create an object of
class L, then the object is shared by R? Not quite sure what it
means...

Jess
 
B

BobR

Jess wrote in message...
Which is commonly refered to as "diamond inheritance".
Thanks again! I haven't used virtual inheritance... What is it to
"share" the same instance? Does it mean that if I create an object of
class L, then the object is shared by R? Not quite sure what it
means...
Jess

Check out "Thinking in C++" Vol 2, '9: Multiple Inheritance' (esp.
'Duplicate subobjects', and 'Virtual base classes').

Get "Thinking in C++", 2nd ed. Volume 1&2 by Bruce Eckel
(available for free here. You can buy it in hardcopy too.):
http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html

It's a short download (approx 992kb).

And/or, look it up in your book(s).
 
J

James Kanze

[...]
Thanks again! I haven't used virtual inheritance... What is it to
"share" the same instance? Does it mean that if I create an object of
class L, then the object is shared by R? Not quite sure what it
means...

If you have the above declarations, it means that if you create
an L, it has its own VB, if you create an R, it has its own VB,
but if you create a MD, there is only one instance of VB in the
hierarchy; the R and the L in the MD share the single VB. (It's
sometimes confusing because you have to declare the inheritance
virtual in L and in R, but the virtuality really only comes into
play when you derive from L and R. But the compiler needs to
know whether VB might be shared or not when it generates the
code for L and R, so there's no way around it.)

If you recall, my original posting had an inheritance graph:

VB
/ \
L R
\ /
MD

Notice that there is only one VB, and that is it the base class
of both L and R. Without the "virtual" in the inheritance, the
graph would be:

VB VB
\ /
L R
\ /
MD

, with two instances of VB. As an interesting sidelight:

In the first case, with virtual inheritance, you can use a
static_cast to go from MD* to VB*, but not the reverse (because
there is a special restriction on static_cast). In the second,
you can use a static_cast to go from VB* to MD*, but not the
reverse (because the cast would be ambiguous: which VB?). You
can use a dynamic_cast to move anywhere in the hierarchy in the
first case, but MD* to VB* is still ambiguous in the second.

Most of the time, when you inherit from an interface, etc., the
inheritance should probably be virtual. You don't often really
need it, but you don't really know that you won't need it until
you hit classes lower down in the hierarchy. And it might be
another user who runs into the problem, and doesn't have the
right to modify your classes. Many people don't, however,
because it is needed so rarely.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,534
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top