Pointer trouble

Started by
7 comments, last by grelle 17 years, 11 months ago
Does anyone know a way around this error without a manual cast? (Some kind of template construct perhaps?)
class Base {};
class Inherited : public Base {};

void Func(Base **pBase);

Inherited *pInherited;
Func(&pInherited); // <-- error C2664
'Func' : cannot convert parameter 1 from 'Inherited **' to 'Base **' Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
Advertisement
You cannot, it's unsafe; as always, you can do it manually, but C++ finds it too dangerous.

This (rather dashing) page explains why: http://www.parashift.com/c++-faq-lite/proper-inheritance.html#faq-21.2

In short, if it were possible you could end up with one derived class' pointer-to-pointer point to another derived class' pointer-to-pointer, causing dangerous behaviour.

I'm not sure how I'd go about going around it, you can always c-style cast, even though that's dangerous, if you know what you're doing (along with the others using your code) it's not a crime against humanity, just a crime against style.
--Jeroen Stout - WebsiteCreator of-Divided
yeah, but in this case I really need the address, and the Base class is an interface that doesn't inherit from anything else.
But that doesn't matter because I only use the adress to store a new pointer during deserialization and thus the whole operation is inherently unsafe. =)

The reason I want to do it automatic is because the code gets really ugly with all those manual casts everywhere. I guess I could do it with macros
If you're sure you won't be doing anything 'wrong' in there, you could maybe use a templated proxy function that takes care of the casting (and possibly template type checking to make sure what you're casting from is inherited off Base)
Quote:Original post by grelle
yeah, but in this case I really need the address


Are you sure? This smells a lot like a situation where you should be passing by reference instead - and typing the parameter in the caller as a Base* even though it happens to point to a Derived object. Assuming the reason for the double-pointer (strongly suggested here by context) is to modify what is being pointed at in the caller, keep in mind that the current setup might also change the exact subtype.
Quote:Assuming the reason for the double-pointer (strongly suggested here by context) is to modify what is being pointed at in the caller, keep in mind that the current setup might also change the exact subtype.

I will in effect decide the subtype when the object is read from a stream. Assuming the stream is not "hacked" it will contain the correct subtype.

However, as you suggested, I could use a const reference to the pointer instead. That would get rid of all manual casts, but I would have to do a const_cast on the reference to modify its value.

Something like this:
Func(Base *const &Ptr) { const_cast<Base *&>(Ptr) = newptr; }

Inherited *pInherited;
Func(pInherited); // <-- No error
If I understand you correctly, you'll be using 'Func' to deserialize objects.. surely then, you don't know the type of the object before it's been deserialized, and as such how can you be passing in a pointer to a pointer to a derived type?

Even if you do know the type (for whatever reason), I think you should let the deserialization function deserialize the object, and pass it back as the base type object. At which point you could do a dynamic cast to assign to your derived type pointer in a safe manner.
Quote:Original post by c2_0
If I understand you correctly, you'll be using 'Func' to deserialize objects.. surely then, you don't know the type of the object before it's been deserialized, and as such how can you be passing in a pointer to a pointer to a derived type?

Even if you do know the type (for whatever reason), I think you should let the deserialization function deserialize the object, and pass it back as the base type object. At which point you could do a dynamic cast to assign to your derived type pointer in a safe manner.


Quoted for emphasis.

Also, don't pass a const reference and then const_cast the constness away, when the whole point of the function is to assign to that parameter. Just pass a non-const reference.
[Zahlman]
Quote:Just pass a non-const reference.
It is as ilegal to pass a non-const reference to Base* as it is to pass a Base** if the type is derived from Base. And with that solution I get the original problem with manual casts.

[c2_0]
Quote:I think you should let the deserialization function deserialize the object, and pass it back as the base type object. At which point you could do a dynamic cast to assign to your derived type pointer in a safe manner.

First of all, I have to be able to assume that the stream is not corrupt. If the stream is corrupt it could generate any kind of bogus data, and dynamic_cast will not solve that. Corrupt streams needs to be handled before the deserialization begins, with other types of verifications.

And I cannot return the newly created object immediatly because the operation is asynchronous. I also need/want all addresses for verification/debug purposes. And it works fine for 'standard' types, as I only pass a reference to them. The only problem I have is with derived pointer types.

I know that const_cast is kind of ugly but that is the easiest solution to my original problem I've found so far...
[edit]actually, I did not find it. Zahlman pointed it out to me, thanks for that =)[/edit]

[c2_0] You mentioned a 'templated proxy function' earlier. I have tried to come up with something, but failed. Do you have any suggestions on this?

This topic is closed to new replies.

Advertisement