Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

C++ casting/rtti problems

37 views
Skip to first unread message

Gregory K. Thomas

unread,
Apr 22, 1999, 3:00:00 AM4/22/99
to
Greetings,

Any help with the following problem would be greatly appreciated.

Is there any reason why performing a downcast from a *virtual* base class
to a derived class would not be allowed?

I have the following declarations.

class MsgType {};
class SSMsgType : public virtual MsgType {};
class RefDataReqMsgType : public virtual RefDataReqType,
public virtual MsgType {};
class SSRefDataReqMsgType : public virtual RefDataReqMsgType,
public virtual SSMsgType {}

Visually, this class hierarchy is as follows.

RefDataReqType <-- RefDataReqMsgType --> MsgType
^ ^
| |
SSRefDataReqMsgType --> SSMsgType

The SUN C++ 5.0 compiler doesn't allow the following when rtti is
disabled.

f(const MsgType &Msg)
{
const RefDataReqMsgType &RefDataReqMsg =
dynamic_cast<const RefDataReqMsgType&>(Msg);
}

According to the documentation, disabling rtti simply turns dynamic casts
into static casts. Our compiler reports the following.

Warning: RTTI disabled, "dynamic_cast<const RefDataReqMsgType&>"
replaced by "static_cast<const RefDataReqMsgType&>".
Error: Using static_cast to convert from const MsgType& to const
RefDataResMsgType& now allowed.

* Here are a few other observations.
o The GNU compiler does not have the same complaint, and it seems to
work correctly during runtime.
o Enabling rtti will remove the compile-time error, but there seems to
be a runtime problem (i.e., core dump). I haven't confirmed that the
runtime problem is caused by this particular issue though, but it
seems very likely since the same code compiled with GNU runs fine.
o Removing "virtual" inheritance will remove the compile-time error.
However, this causes the class hierarchy to be changed to the
following (notice MsgType is duplicated).

RefDataReqType <-- RefDataReqMsgType --> MsgType
^
|
SSRefDataReqMsgType --> SSMsgType --> MsgType

This cast seems legitimate to me, does anyone have any ideas why the
compiler is complaining?

Does anyone know a potential workaround?

BTW, we have the following constraints.
(1) We have to link with 3rd party libraries compiled by the SUN C++
compiler, so we can't use GNU g++.
(2) Other libraries are compiled without rtti support, so (barring some
rtti workaround) my stuff also needs to compile without rtti support.

Thanks in advance,
Gregory K. Thomas (tho...@lucent.com)

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Martin von Loewis

unread,
Apr 23, 1999, 3:00:00 AM4/23/99
to
"Gregory K. Thomas" <tho...@lucent.com> writes:

> Is there any reason why performing a downcast from a *virtual* base
class
> to a derived class would not be allowed?

Yes. I doubt that you could compile the code as posted with gcc, I get
the message

c.cc:9: cannot dynamic_cast `+x' (of type `const class MsgType &') to
type `const class RefDataReqMsgType &'

This is because the base class MsgType is not polymorphic: You need to
have virtual functions in the base you are dynamic_casting from.

> The SUN C++ 5.0 compiler doesn't allow the following when rtti is
> disabled.

And rightly so: When I compile this with gcc -fno-rtti, I get

c.cc: In function `void foo(const class MsgType &)':
c.cc:9: warning: taking dynamic typeid of object without -frtti

> According to the documentation, disabling rtti simply turns dynamic
casts
> into static casts.

Ok. The standard is silent about 'disabling rtti': In standard C++,
RTTI is always there.

It is probably a good fall-back to replace it dynamic with static
casts. g++ uses a different fall-back: Emitting the same code, and
then potentially running into run-time crashs.

Of course, you can't static_cast from a virtual base to a derived
class, so if that is the CC fall-back, you can't dynamic_cast from a
virtual base, period.

> o The GNU compiler does not have the same complaint, and it seems to
> work correctly during runtime.

I find that observation questionable. In my example code below, code
compile with gcc -fno-rtti crashes on Sparc. I would expect it to
crash: Without the virtual typeid function, the runtime system will
call a null pointer when attempting to determine the dynamic type of
an object.

> o Enabling rtti will remove the compile-time error, but there seems to
> be a runtime problem (i.e., core dump). I haven't confirmed that the
> runtime problem is caused by this particular issue though, but it
> seems very likely since the same code compiled with GNU runs
> fine.

This is not necessarily the case. Without complete source, it is very
hard to guess.

> This cast seems legitimate to me, does anyone have any ideas why the
> compiler is complaining?

Yes, it is illegal in standard C++ to cast from a virtual base.

> Does anyone know a potential workaround?

Avoid having to dynamic_cast, by passing always pointers to the
complete type. If that is not possible, enable rtti. If that breaks,
as you say, investigate the problem. Then either fix the bug in your
code or upgrade to a newer compiler version.

> (2) Other libraries are compiled without rtti support, so (barring some
> rtti workaround) my stuff also needs to compile without rtti
support.

I don't know CC: Is it explicitly stated that you can't mix code
compiled with and without rtti? In g++, you can...

Regards,
Martin

Seefeld Stefan

unread,
Apr 24, 1999, 3:00:00 AM4/24/99
to
On 22 Apr 1999, Gregory K. Thomas wrote:

> Is there any reason why performing a downcast from a *virtual* base class
> to a derived class would not be allowed?
>

> I have the following declarations.
>
> class MsgType {};
> class SSMsgType : public virtual MsgType {};
> class RefDataReqMsgType : public virtual RefDataReqType,
> public virtual MsgType {};
> class SSRefDataReqMsgType : public virtual RefDataReqMsgType,
> public virtual SSMsgType {}
>
> Visually, this class hierarchy is as follows.
>
> RefDataReqType <-- RefDataReqMsgType --> MsgType
> ^ ^
> | |
> SSRefDataReqMsgType --> SSMsgType
>

> The SUN C++ 5.0 compiler doesn't allow the following when rtti is
> disabled.
>

> f(const MsgType &Msg)
> {
> const RefDataReqMsgType &RefDataReqMsg =
> dynamic_cast<const RefDataReqMsgType&>(Msg);
> }
>

> According to the documentation, disabling rtti simply turns dynamic casts

> into static casts. Our compiler reports the following.
>
> Warning: RTTI disabled, "dynamic_cast<const RefDataReqMsgType&>"
> replaced by "static_cast<const RefDataReqMsgType&>".
> Error: Using static_cast to convert from const MsgType& to const
> RefDataResMsgType& now allowed.

it is not only not allowed, it is (in most cases) not possible.
Look at the memory layout of a derived class. The derived class is
sizeof(parent class) + sizeof(additional data from child class) large.
to get from the child to the parent (via a static cast) you simply perform
a shift of fixed size (which is known to the compiler since he lays out
the classes. However, if you derive virtually, you normally don't know
the size of this shift since the number of intermediate classes in the
inheritance lattice is not known. To get to the parent anyway, you need
information which is added with rtti. That's the way dynamic_cast works.

The fact that in a couple of cases the compiler might be able to figure
out the shift doesn't change the fact that generally it is not possible.

> * Here are a few other observations.

> o The GNU compiler does not have the same complaint, and it seems to
> work correctly during runtime.

May be if all is defined within the same module, this kind of optimization
is possible, I don't know.

> o Enabling rtti will remove the compile-time error, but there seems to
> be a runtime problem (i.e., core dump). I haven't confirmed that the
> runtime problem is caused by this particular issue though, but it
> seems very likely since the same code compiled with GNU runs fine.

Be careful not to mix code compiled with and without rtti. The memory
layout for objects is different. That very likely causes seg faults.

> o Removing "virtual" inheritance will remove the compile-time error.

Sure.See above.

> Does anyone know a potential workaround?

use rtti. It's the standard.

> BTW, we have the following constraints.
> (1) We have to link with 3rd party libraries compiled by the SUN C++
> compiler, so we can't use GNU g++.

Oh, and these libraries are not compiled with rtti enabled, are they ?

> (2) Other libraries are compiled without rtti support, so (barring some
> rtti workaround) my stuff also needs to compile without rtti support.

youp.

Stefan

Steve Clamage

unread,
Apr 24, 1999, 3:00:00 AM4/24/99
to
"Gregory K. Thomas" <tho...@lucent.com> writes:


> Any help with the following problem would be greatly appreciated.

> Is there any reason why performing a downcast from a *virtual* base class


>to a derived class would not be allowed?

It was never allowed in C++ until dynamic_cast was introduced.
Now you can downcast a pointer or referece to a virtual base class
if the class is polymorphic and you use dynamic_cast, but not
otherwise.

Consider:

class VB { ... };
class A : public virtual VB { ... };
class B : public virtual VB { ... };
class C : public B, public A { ... };
class D : public A, public B { ... };

No matter what method the compiler uses to lay out classes,
the relative positions of VB and A cannot be the same in
each of B, C, and D.

Thus, there is no way to know how to make the pointer adjustment
from VB to A without knowing the type of the most-derived object.
Dynamic_cast can get the needed information via RTTI if the
classes are polymorphic.

--
Steve Clamage, stephen...@sun.com

Gregory K. Thomas

unread,
Apr 24, 1999, 3:00:00 AM4/24/99
to
Martin,

> Yes. I doubt that you could compile the code as posted with gcc, I get
> the message
>
> c.cc:9: cannot dynamic_cast `+x' (of type `const class MsgType &') to
> type `const class RefDataReqMsgType &'
>
> This is because the base class MsgType is not polymorphic: You need to
> have virtual functions in the base you are dynamic_casting from.

Sorry. I didn't include the complete declaration in order to simplify my
posting. The "MsgType" class defines several virtual functions.

>
> Of course, you can't static_cast from a virtual base to a derived

> class, ...

Does the standard address trying to perform a static_cast from a virtual
base class to a derived class? Can you give me a reference?

>
> > This cast seems legitimate to me, does anyone have any ideas why the
> > compiler is complaining?
>
> Yes, it is illegal in standard C++ to cast from a virtual base.

I don't understand why a static_cast from a *virtual* base is not allowed,
but a static_cast from a non-virtual base is permitted. My understanding is
that virtual inheritance simply makes the base class shared by one or more
subclasses.

>
> > Does anyone know a potential workaround?
>

I've discovered a workaround which is to remove the "virtual" from the
inheritance of "MsgType".

class MsgType {};
class SSMsgType : public virtual MsgType {};
class RefDataReqMsgType : public virtual RefDataReqType,

public MsgType {};


class SSRefDataReqMsgType : public virtual RefDataReqMsgType,
public virtual SSMsgType {}

I thought that this would create two instances of "MsgType" within the
hierarchy. However, according to the class hierarchy graph generated by Sun's
Workshop, "MsgType" only occurs once.

>
> I don't know CC: Is it explicitly stated that you can't mix code
> compiled with and without rtti? In g++, you can...

Whenever we compile our libraries without rttt, compile my subsystem with
rtti, and try to link the two together we get unresolved symbols from the
linker. It's not explicitly stated though.

Thank you for your comments.

Best regards,
Gregory K. Thomas

Martin von Loewis

unread,
Apr 26, 1999, 3:00:00 AM4/26/99
to
"Gregory K. Thomas" <tho...@lucent.com> writes:

> Does the standard address trying to perform a static_cast from a virtual
> base class to a derived class? Can you give me a reference?

Yes, it does. 5.2.9, [expr.static.cast]/8 says

>> An rvalue of type "pointer to cv1 B", where B is a class type, can
>> be converted to an rvalue of type "pointer to cv2 D", where D is a
>> class derived (clause 10) from B, if a valid standard conversion
>> from "pointer to D" to "pointer to B" exists (4.10), cv2 is the
>> same cv­qualification as, or greater cv­qualification than, cv1,
>> and B is not a virtual base class of D.


> I don't understand why a static_cast from a *virtual* base is not allowed,
> but a static_cast from a non-virtual base is permitted. My understanding is
> that virtual inheritance simply makes the base class shared by one or more
> subclasses.

Yes, it does. However, static-casting means that you have to adjust
the pointer, based on static knowledge. For a virtual base, you can't
know statically by what amount you have to adjust the pointer.

> I've discovered a workaround which is to remove the "virtual" from the
> inheritance of "MsgType".
>
> class MsgType {};
> class SSMsgType : public virtual MsgType {};
> class RefDataReqMsgType : public virtual RefDataReqType,
> public MsgType {};
> class SSRefDataReqMsgType : public virtual RefDataReqMsgType,
> public virtual SSMsgType {}
>
> I thought that this would create two instances of "MsgType" within the
> hierarchy. However, according to the class hierarchy graph generated by Sun's
> Workshop, "MsgType" only occurs once.

Well, the compiler is free to optimize-away empty base
classes. However, you can't static_cast from MsgType* to
SSRefDataReqMsgType*, because the conversion in the other direction is
ambiguous. So, if CC accepts that, it is an error.

Regards,
Martin

0 new messages