2

Is conversion from Base* to Derived* always allowed ? Is conversion from const Base* to const Derived* always allowed ?

I am using Qt QSharedPointers. I have a QSharedPointer to Base object, that I want to convert to a QSharedPointer to a Derived object. I check beforehand that pointee is of type Derived.

Is it possible with 100% chance of success with

  • static_cast<QSP<Derived>>
  • dynamic_cast<QSP<Derived>>
  • a direct cast QSP<Derived>(my_base_pointer)

?

For example, for direct conversion:

QSP<Derived> inpf = QSP<Derived>(my_base_pointer) ;

i have error

Error 1 error C2440: 'initializing' : cannot convert from 'Base *' to 'Derived *'

with my_base_pointer of type const QSP<Base>.

Is it because of constness ? Should I const_cast on top of that ? I guess constness is not root cause, since if i

const QSP<Derived> inpf = static_cast<const QSP<Derived>>(my_base_pointer);

same error occurs.

kiriloff
  • 25,609
  • 37
  • 148
  • 229

5 Answers5

6

You're feeding the QSP<Derived> constructor a Base* pointer, which won't work. As long as you're sure the pointer really is a Derived* you should be able to static_cast it:

QSP<Derived> inpf = QSP<Derived>(static_cast<Derived*>(my_base_pointer)) ;

If the base class has at least one virtual function, it's safer to use dynamic_cast in this situation since that's what it was created for. If the pointer isn't actually a pointer to the derived class you'll get a NULL pointer.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • Mark, kick me in the head and remind me whether it is possible to use `dynamic_cast<>` to throw an exception if it fails, or whether you have to code that logic yourself. I honestly don't remember. Just curious.(and +1) – WhozCraig Apr 22 '13 at 19:02
  • @MarkRansom what about `QSP inpf = static_cast(my_base_pointer) ;` with `my_base_pointer` of type `QSP` – kiriloff Apr 22 '13 at 19:05
  • @WhozCraig, I think I have it wrong - `dynamic_cast` appears to throw always according to [cppreference.com](http://en.cppreference.com/w/cpp/language/dynamic_cast). I don't know how I got the impression it would return a NULL. I'll have to change my answer. – Mark Ransom Apr 22 '13 at 19:07
  • @antitrust I don't know the details of Qt shared pointers so I don't know if it would handle that, it's completely up to the Qt implementation. – Mark Ransom Apr 22 '13 at 19:09
  • @MarkRansom `std::bad_cast` will happen with references, not pointers. "Otherwise, the runtime check fails. *If the dynamic_cast is used on pointers, the null pointer value of type new_type is returned.* If it was used on references, the exception std::bad_cast is thrown." – Yakk - Adam Nevraumont Apr 22 '13 at 19:13
  • @Yakk, now I'm doubly an idiot. Thanks. I've edited the answer back to my original and I'm going to need to check my reading comprehension in the future. – Mark Ransom Apr 22 '13 at 19:16
  • @WhozCraig, you get a NULL pointer if you're casting a pointer and a `std::bad_cast` exception if you're casting a reference. You don't have any control over it. – Mark Ransom Apr 22 '13 at 19:21
  • @MarkRansom Totally makes sense when you think about it. Can init a pointer to NULL, no such valid beast on a ref-initializer. Sorry for the temporary insanity. Good answer(s). – WhozCraig Apr 22 '13 at 19:32
1

What you are trying to do is called a downcast. For details, check this answer.

Community
  • 1
  • 1
Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
  • then just consider my question to be how to downcast a QSharedPointer under normal pressure and temperature conditions. `QSP inpf_filter = static_cast>(my_base_QSP) ;` is not working and i am sad. – kiriloff Apr 22 '13 at 19:14
0

There is no implicit conversion from Base* to Derived*. That's because a pointer to Base does not have to point to a Derived object. If you're sure that it does, use a static_cast: static_cast<Derived*>(base_pointer). If you're not sure, and Base has at least one virtual function, use a dynamic_cast: dynamic_cast<Derived*>(base_pointer); this will do the conversion if the pointer points to an object of type Derived, and it will return a null pointer if it does not.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
0

As suggested in comments, question is about QSharedPointer, and generic answer for conversion Base* to Derived* does not fit this special case.

Diving in Qt docs, we find interesting member method for QSharedPointer, staticCast.

First, i came up with this code:

QSP<Derived> inpf_filter = my_base_QSP->staticCast<Derived>() ; 

Since my QSP is a pointer type, I am -> above calls staticCast() not on the QSP but on the pointee. So, I had an error again: staticCast() is not a member of Base class. I corrected into

QSP<Derived> inpf_filter = my_base_QSP.staticCast<Derived>() ; 

and this compiles. QSharedPointer also supports dynamicCast(). In this, if cast cannot be performed, null pointer is returned.

kiriloff
  • 25,609
  • 37
  • 148
  • 229
0

QSharedPointers have an entire set of casting mechanisms:

http://qt-project.org/doc/qt-4.8/qsharedpointer.html#qSharedPointerCast

For a QSharedPointer<U>:

QSharedPointer ( const QSharedPointer<T> & other )
QSharedPointer<X>   constCast () const
QSharedPointer<X>   dynamicCast () const
QSharedPointer<X>   objectCast () const
QSharedPointer<X>   staticCast () const

The constructor works if T is a subtype of U.

const, dynamic and static cast work like the _cast operators of C++.

object does a qobject_cast.

Performing _cast operators on shared pointer types is generally a bad idea if you store the result in another shared pointer -- in order to safely cast a shared pointer that is non-intrusive, you need to do shared-pointer aware casting.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524