Connecting Tech Pros Worldwide Help | Site Map

inheritance question

Bruno van Dooren
Guest
 
Posts: n/a
#1: Nov 16 '05
Hi all,

I have 2 classes:
class A{...};
class B : public A{...}

i manage all B instances in an array of A*.
A is a generic type that serves as a base type for a resource manager.

when i try to do

B* objectReference = dynamic_cast<B*>(aPointerToAnInstanceOfA);

i get compiler error:
error C2683: dynamic_cast : 'ManagedResource' is not a polymorphic type

apparently it is not enough that B inherits from A.
is there an elegant solution to this? or do i need to create a virtual dummy
method, however silly that would be?

kind regards,
Bruno.


Carl Daniel [VC++ MVP]
Guest
 
Posts: n/a
#2: Nov 16 '05

re: inheritance question


Bruno van Dooren wrote:[color=blue]
> Hi all,
>
> I have 2 classes:
> class A{...};
> class B : public A{...}
>
> i manage all B instances in an array of A*.
> A is a generic type that serves as a base type for a resource manager.
>
> when i try to do
>
> B* objectReference = dynamic_cast<B*>(aPointerToAnInstanceOfA);
>
> i get compiler error:
> error C2683: dynamic_cast : 'ManagedResource' is not a polymorphic
> type
>
> apparently it is not enough that B inherits from A.
> is there an elegant solution to this? or do i need to create a
> virtual dummy method, however silly that would be?[/color]

You need to have at least one virtual method for dynamic_cast to succeed.
Normally, in a structure such as you describe, your 'A' class should at
least have a virtual destructor.

-cd


Sin
Guest
 
Posts: n/a
#3: Nov 16 '05

re: inheritance question


> I have 2 classes:[color=blue]
> class A{...};
> class B : public A{...}
>
> i manage all B instances in an array of A*.
> A is a generic type that serves as a base type for a resource manager.
>
> when i try to do
>
> B* objectReference = dynamic_cast<B*>(aPointerToAnInstanceOfA);
>
> i get compiler error:
> error C2683: dynamic_cast : 'ManagedResource' is not a polymorphic type
>
> apparently it is not enough that B inherits from A.
> is there an elegant solution to this? or do i need to create a virtual[/color]
dummy[color=blue]
> method, however silly that would be?[/color]


An anal C++ programmer would tell you that if you need to cast your design
is broken. I usually tend to agree with that theory... How would you know
that aPointerToAnInstanceOfA really is a B instance? It almost has to do
with some twisted trick...

As to why this error occurs, did you look at the help of error message
C2683? Here it is :

====================
Compiler Error C2683

dynamic_cast : 'class' is not a polymorphic type

The dynamic_cast operator cannot be used to convert from a non-polymorphic
class, that is, a class that does not define any virtual functions.

You can use the static_cast operator to perform conversions of
non-polymorphic types; note, however, that static_cast does not perform a
run-time check.

The following is an example of this error:

class B { };
class D : public B { };

void f(B* pb)
{
D* pd1 = dynamic_cast<D*>(pb); // error
}
====================

I don't know the reason of this "limitation" though. I would have expected
this to work well. I would simply put the destructor of A virtual...

BTW: You might be interrested to know dynamic_cast, even though it's
standard C++, is not supported by all C++ compilers. I've had this problem
with Watcom on QNX a little while ago...

Alex.


Sean Cavanaugh
Guest
 
Posts: n/a
#4: Nov 16 '05

re: inheritance question


> dynamic_cast : 'class' is not a polymorphic type[color=blue]
>
> The dynamic_cast operator cannot be used to convert from a non-polymorphic
> class, that is, a class that does not define any virtual functions.
>
> You can use the static_cast operator to perform conversions of
> non-polymorphic types; note, however, that static_cast does not perform a
> run-time check.
>[/color]

While static_cast doesn't do a runtime check, it at least prevents you
from casting to something that is compltely impossible, that a C-style
or reinterpret_cast would let you do. If you know that an A* object is
really a B*, then static_cast is definitely a (relatively) safe fast way
to do it.

Sin
Guest
 
Posts: n/a
#5: Nov 16 '05

re: inheritance question


> While static_cast doesn't do a runtime check, it at least prevents you[color=blue]
> from casting to something that is compltely impossible, that a C-style
> or reinterpret_cast would let you do. If you know that an A* object is
> really a B*, then static_cast is definitely a (relatively) safe fast way
> to do it.[/color]

If there is multiple inheritance involved there can be big hickups with
static_cast or C-style cast... Here's an example I've been confronted with
recently.

#include <stdio.h>
#include <conio.h>

class Transport {
public:
virtual void Send() = 0;
virtual void Receive() = 0;
virtual void Wait() = 0;
};

class Client {
public:
virtual void Connect() = 0;
};

class TransportUDP : public Transport {
public:
virtual void Send() {
printf("TransportUDP::Send()\n");
}

virtual void Receive() {
printf("TransportUDP::Receive()\n");
}

virtual void Wait() {
printf("TransportUDP::Wait()\n");
}
};

class TransportUDPClient : public TransportUDP, public Client {
public:
virtual void Connect() {
printf("TransportUDPClient::Connect()\n");
}
};

void main(void) {
Transport *pTransport= new TransportUDPClient();

// This does not call TransportUDPClient::Connect()
// but TransportUDP::Send()
static_cast<Client*>(pTransport)->Connect();

pTransport->Wait();
pTransport->Receive();
pTransport->Send();

delete pTransport;

getch();
}


Even though pTransport actually points to a TransportUDPClient, thus Client
instance, only dynamic_cast would allow me to call the right function
(Connect)...

Alex.


Sean Cavanaugh
Guest
 
Posts: n/a
#6: Nov 16 '05

re: inheritance question


Your code generated the following error:

foo.cpp(43) : error C2440: 'static_cast' : cannot convert from Transport
*' to 'Client *'
Types pointed to are unrelated; conversion requires
reinterpret_cast, C-style cast or function-style cast


The static_cast failed, as it should have.


Sin wrote:[color=blue][color=green]
>>While static_cast doesn't do a runtime check, it at least prevents you
>>from casting to something that is compltely impossible, that a C-style
>>or reinterpret_cast would let you do. If you know that an A* object is
>>really a B*, then static_cast is definitely a (relatively) safe fast way
>>to do it.[/color]
>
>
> If there is multiple inheritance involved there can be big hickups with
> static_cast or C-style cast... Here's an example I've been confronted with
> recently.
>
> #include <stdio.h>
> #include <conio.h>
>
> class Transport {
> public:
> virtual void Send() = 0;
> virtual void Receive() = 0;
> virtual void Wait() = 0;
> };
>
> class Client {
> public:
> virtual void Connect() = 0;
> };
>
> class TransportUDP : public Transport {
> public:
> virtual void Send() {
> printf("TransportUDP::Send()\n");
> }
>
> virtual void Receive() {
> printf("TransportUDP::Receive()\n");
> }
>
> virtual void Wait() {
> printf("TransportUDP::Wait()\n");
> }
> };
>
> class TransportUDPClient : public TransportUDP, public Client {
> public:
> virtual void Connect() {
> printf("TransportUDPClient::Connect()\n");
> }
> };
>
> void main(void) {
> Transport *pTransport= new TransportUDPClient();
>
> // This does not call TransportUDPClient::Connect()
> // but TransportUDP::Send()
> static_cast<Client*>(pTransport)->Connect();
>
> pTransport->Wait();
> pTransport->Receive();
> pTransport->Send();
>
> delete pTransport;
>
> getch();
> }
>
>
> Even though pTransport actually points to a TransportUDPClient, thus Client
> instance, only dynamic_cast would allow me to call the right function
> (Connect)...
>
> Alex.
>
>[/color]

Sin
Guest
 
Posts: n/a
#7: Nov 16 '05

re: inheritance question


> Your code generated the following error:[color=blue]
>
> foo.cpp(43) : error C2440: 'static_cast' : cannot convert from Transport
> *' to 'Client *'
> Types pointed to are unrelated; conversion requires
> reinterpret_cast, C-style cast or function-style cast
>
>
> The static_cast failed, as it should have.[/color]


Umm I actually hand modified the code a bit before sending it. Should have
tested it, sorry.

The actual code is using dynamic_cast, and works just fine. The initial code
was using a C-style cast, which compiled fine, but did not work as I
initially expected (it would call the wrong function).

I though I remembered using static_cast with the same results, but obviously
not!

Sorry again.

Alex.


Sean Cavanaugh
Guest
 
Posts: n/a
#8: Nov 16 '05

re: inheritance question


Ahh well thats the difference right there. The C-style cast is evil :)
It attempts to do the equivalent of a static_cast, followed by a
const_cast, then reinterpret_cast if all else fails. The problem is,
when all else fails, reinterpret_cast is usually not what you want (in
C++ code). static_cast is substantially safer and using it all the
time lets you notice when you _really_ need to bust out a
reinterpret_cast and the necessary work to make THAT safe.


Sin wrote:[color=blue][color=green]
>>Your code generated the following error:
>>
>>foo.cpp(43) : error C2440: 'static_cast' : cannot convert from Transport
>>*' to 'Client *'
>> Types pointed to are unrelated; conversion requires
>>reinterpret_cast, C-style cast or function-style cast
>>
>>
>>The static_cast failed, as it should have.[/color]
>
>
>
> Umm I actually hand modified the code a bit before sending it. Should have
> tested it, sorry.
>
> The actual code is using dynamic_cast, and works just fine. The initial code
> was using a C-style cast, which compiled fine, but did not work as I
> initially expected (it would call the wrong function).
>
> I though I remembered using static_cast with the same results, but obviously
> not!
>
> Sorry again.
>
> Alex.
>
>[/color]

Dan Daly
Guest
 
Posts: n/a
#9: Nov 16 '05

re: inheritance question


Bruno,

I think the fact that you encountered this issue is an indication that the
design is sub-optimal. The design should help you, not hinder you.

What is the reason for putting Connect in Client?

dan

"Sin" <broa29@hotmail.com> wrote in message
news:e#rp69GeDHA.1752@TK2MSFTNGP10.phx.gbl...[color=blue][color=green]
> > So you agree that casting in itself is NOT an indication of broken[/color][/color]
design?[color=blue]
>
> Hehe it was not Sean but me who made the comment about the broken design.
> The way I said it was :
>[color=green]
> > An anal C++ programmer would tell you that if you need
> > to cast your design is broken. I usually tend to agree
> > with that theory..."[/color]
>
> It was subtle, but there was room for exception... I would at least look[/color]
at[color=blue]
> how a cast could be avoided. You explained your design but I didn't quite
> grasp it (never worked much with templates), so I can't really comment.
>
> Alex.
>
>[/color]


Closed Thread


Similar .NET Framework bytes