inheritance question | | |
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. | | | | 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 | | | | 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. | | | | 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. | | | | 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. | | | | 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] | | | | 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. | | | | 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] | | | | 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] |  | Similar .NET Framework bytes | | | /bytes/about
We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights.
Get the best answers to your questions from over 226,272 network members.
|