Results 1 to 11 of 11

Thread: Is the down casting right, and why dynamic_cast fails?

  1. #1
    Join Date
    Nov 2015
    Posts
    17
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Is the down casting right, and why dynamic_cast fails?

    Hello guys,
    here I have a snippet of code and it would be very helpful, if you can explain why the second dynamic_cast fails and if the static_cast is the way to do it.

    There are three classes Base, MyString and MyList. MyString and MyList are derived from Base. MyList is a template-class
    Qt Code:
    1. #include <QCoreApplication>
    2. #include <QDebug>
    3.  
    4. class Base
    5. {
    6. public:
    7. Base(){
    8.  
    9. }
    10.  
    11. virtual ~Base(){
    12. qDebug() << "~Base()";
    13. }
    14. };
    15.  
    16. class MyString : public Base
    17. {
    18. public:
    19. QString str;
    20.  
    21. public:
    22. MyString(const QString& str) : Base(), str(str){
    23.  
    24. }
    25.  
    26. virtual ~MyString(){
    27. qDebug() << "~MyString()";
    28. }
    29. };
    30.  
    31. template <class T>
    32. class MyList : public QList<T>, public Base
    33. {
    34. public:
    35. MyList<T>():QList<T>(){
    36.  
    37. }
    38.  
    39. MyList<T>(QList<T> h):QList<T>(h){
    40.  
    41. }
    42.  
    43. virtual ~MyList<T>(){
    44. qDebug() << "~MyList()";
    45. }
    46. };
    47.  
    48. Base* createMyList()
    49. {
    50. MyList<Base*>* myList = new MyList<Base*>();
    51. myList->append(new MyString("joey potter"));
    52. myList->append(new MyString("allen harper"));
    53. myList->append(new MyString("charlie harper"));
    54. myList->append(new MyString("john mcclane"));
    55.  
    56. return myList;
    57. }
    58.  
    59. int main(int argc, char *argv[])
    60. {
    61. QCoreApplication a(argc, argv);
    62. Q_UNUSED(a);
    63.  
    64. MyList<Base*>* myList = new MyList<Base*>();
    65. myList->append(new MyString("string1"));
    66.  
    67. //I know that first element is from class MyString so static_cast is sufficient
    68. Q_ASSERT(dynamic_cast<MyString*>(myList->first()) != NULL);// ok
    69. Q_ASSERT(static_cast<MyString*>(myList->first()) != NULL);// ok
    70.  
    71. MyList<MyString*>* anotherList = static_cast<MyList<MyString*>*>(createMyList());
    72. Q_ASSERT(anotherList != NULL);// ok
    73.  
    74. MyList<MyString*>* differentList = dynamic_cast<MyList<MyString*>*>(createMyList());
    75. Q_ASSERT(differentList != NULL);// ASSERT: "differentList != NULL" in file ../dynamic_cast_test/main.cpp, line 74
    76.  
    77.  
    78.  
    79.  
    80.  
    81.  
    82.  
    83. //free ram
    84. QListIterator<Base*> lit1(*myList);
    85. while(lit1.hasNext()){
    86. delete lit1.next();
    87. }
    88. delete myList;
    89.  
    90. QListIterator<MyString*> lit2(*anotherList);
    91. while(lit2.hasNext()){
    92. delete lit2.next();
    93. }
    94. delete anotherList;
    95.  
    96. QListIterator<MyString*> lit3(*differentList);
    97. while(lit3.hasNext()){
    98. delete lit3.next();
    99. }
    100. delete differentList;
    101.  
    102. return 0;
    103. }
    To copy to clipboard, switch view to plain text mode 

    Why does following cast fail?
    Qt Code:
    1. MyList<MyString*>* differentList = dynamic_cast<MyList<MyString*>*>(createMyList())
    To copy to clipboard, switch view to plain text mode 
    Cause MyList<Base*>* is completely different from MyList<MyString*>* and the dynamic check is technically impossible ?

    But can I do a static_cast(no dynamic checks), cause I know it's a MyList<MyString*>*? Is this cast is safe?

    thank you
    Last edited by QtCrawler; 8th December 2015 at 11:10.

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Is the down casting right, and why dynamic_cast fails?

    If createMyList() returns Base* but actually returns a pointer to an object of MyList<MyString*>, then the dynamic cast should work.

    If createMyList() returns MyList<Base*>* then this is not a base type of MyList<MyString*>, so the dynamic cast will return 0 and the static_cast will likely also not work (since the target is not a subclass of the source).

    Cheers,
    _

  3. The following user says thank you to anda_skoa for this useful post:

    QtCrawler (9th December 2015)

  4. #3
    Join Date
    Nov 2015
    Posts
    17
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Is the down casting right, and why dynamic_cast fails?

    thank you. but why the static_cast works properly in my snippet? Does it work accidentally?
    And what's the best way to cast, if it's like in my code. you have a pointer Base* which is actually a pointer of MyList<Base*>* and you want to cast to MyList<MyString*>*. Do we have to do it in two steps?
    Last edited by QtCrawler; 8th December 2015 at 14:57.

  5. #4
    Join Date
    Nov 2015
    Posts
    17
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Is the down casting right, and why dynamic_cast fails?

    And what's the best way to cast, if it's like in my code. you have a pointer Base* which is actually a pointer of MyList<Base*>* and you want to cast to MyList<MyString*>*. Do we have to do it in two steps?
    Does anybody know an answer to the question above?

  6. #5
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Is the down casting right, and why dynamic_cast fails?

    Your code is more than a little bit confusing. Why do you use Base as the base class for both the list -and- the things in the list? C++ inheritance is intended to express "is-a" relationships: a MyString is-a Base. But your code also claims that MyList< Base * > also is-a Base. You're trying to use this empty, bogus Base class so you can cast things to each other that can't really be cast.

    A MyList< Base * > is a different class than a MyList< MyString * >, even if the contents of each list can be up or down-cast to each other.

    A static cast works because a static cast says, "I don't care if the thing I am trying to cast is completely unrelated to the thing I'm trying to cast it to, just do it", so of course it works for your case. Dynamic casting doesn't work because the two list types are unrelated even if their contents are. At best, you might be able to dynamically cast the MyList< Base * >* to a Base *, and then dynamically cast that to a MyList< MyString * >*, but then your code says you could also cast it to a MyString * (which of course it isn't) by virtue of the confused inheritance tree you've defined.

  7. #6
    Join Date
    Nov 2015
    Posts
    17
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Is the down casting right, and why dynamic_cast fails?

    Thank you for your explanation. But what's the reason to use two dynamic casts instead of two static casts(or maybe one static cast). I thought I need dynamic casts just in cases, where I'm not sure if the pointer holds the to-casting-pointer or not at runtime.

    In serialisaton (i.e xml-communication between client and server)implementations I found such an inheritance design. A list should be serializeable and a string too, so they are derived classes from one base class.
    Last edited by QtCrawler; 11th December 2015 at 13:07.

  8. #7
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Is the down casting right, and why dynamic_cast fails?

    In serialisation (i.e xml-communication between client and server)implementations I found such an inheritance design. A list should be serializeable and a string too, so they are derived classes from one base class.
    That's a quite different use of the concept. Just like in Qt, all classes that can have properties, signals, slots, and so forth inherit from QObject, in the serialization example, they undoubtedly inherit from a base class that defines the methods required by a serializable object. The base class isn't there to provide a workaround for anything, it defines an interface which all serializable objects must implement, and establishes a true "is-a" relationship for derived classes.

    Your "Base" class doesn't define anything, doesn't represent anything other than an empty name. You aren't using it to define the behavior and semantics of a class hierarchy, you're trying to force an unnatural relationship between classes that aren't related. This isn't how inheritance in C++ is intended to be used.

    Static casting does no type-checking, no verification that the first type can actually be cast to the second type. It's a brute force way to do something that is generally unsafe and often incorrect. If dynamic casting won't work, it means you are trying to do something that shouldn't be done, and so you shouldn't be using a static cast to force the compiler to accept it.

  9. The following user says thank you to d_stranz for this useful post:

    QtCrawler (14th December 2015)

  10. #8
    Join Date
    Nov 2015
    Posts
    17
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Is the down casting right, and why dynamic_cast fails?

    Thank you very much for your help.
    That's a quite different use of the concept. Just like in Qt, all classes that can have properties, signals, slots, and so forth inherit from QObject, in the serialization example, they undoubtedly inherit from a base class that defines the methods required by a serializable object. The base class isn't there to provide a workaround for anything, it defines an interface which all serializable objects must implement, and establishes a true "is-a" relationship for derived classes.

    Your "Base" class doesn't define anything, doesn't represent anything other than an empty name. You aren't using it to define the behavior and semantics of a class hierarchy, you're trying to force an unnatural relationship between classes that aren't related. This isn't how inheritance in C++ is intended to be used.
    I totally agree with you. I provided that example not, cause it's the common use and the sense of inheritence in c++. I provided it, to point out the casting issue I've been trying to understand.


    Added after 54 minutes:


    One last question: If there aren't two cast steps necessary. I. e.
    Qt Code:
    1. MyString* myString = dynamic_cast<MyString*>(baseObject);
    To copy to clipboard, switch view to plain text mode 

    Is it ok to use static_cast?

    At best, you might be able to dynamically cast the MyList< Base * >* to a Base *, and then dynamically cast that to a MyList< MyString * >*, but then your code says you could also cast it to a MyString * (which of course it isn't) by virtue of the confused inheritance tree you've defined.
    I tried your advice, but without success:
    Qt Code:
    1. MyList<MyString*>* differentList2 = dynamic_cast<MyList<MyString*>*>(dynamic_cast<Base*>(createMyList()));
    2. //differentList2 is a Null-Pointer
    To copy to clipboard, switch view to plain text mode 
    Do you know the reason?
    Last edited by QtCrawler; 14th December 2015 at 09:40.

  11. #9
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Is the down casting right, and why dynamic_cast fails?

    Do you know the reason?
    You need to break the compound dynamic cast statement into two statements so you can see which of the two casts is the one that fails. I suspect that you aren't going to be able to outwit the compiler on this one, because it knows as well as you do that MyList< MyString * > and MyList< Base *> are different classes that cannot be interconverted even if the contents can be.

    Why don't you take a step back and figure out why simply using MyList< Base * > everywhere isn't adequate? If all of the things you want to put in lists inherit from Base, then you can always construct lists containing any of the inherited class pointers. You can even mix list content pointers if you want. You pass MyList< Base * > pointers everywhere, and do your dynamic casting on the pointers in the list, not the list itself.

    I don't know what you intend to do with your list contents, but if you are clever with the interface you design for Base, you may not have to do any type casting at all. A virtual function in Base, reimplemented in each derived class, could be called as you iterate over the list. Because it is virtual, the compiler will cause the appropriate derived class method to be executed. So a virtual Base:: doSomething() method executed on a list of MyString pointers actually calls MyString:: doSomething().

  12. #10
    Join Date
    Nov 2015
    Posts
    17
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Is the down casting right, and why dynamic_cast fails?

    You need to break the compound dynamic cast statement into two statements so you can see which of the two casts is the one that fails. I suspect that you aren't going to be able to outwit the compiler on this one, because it knows as well as you do that MyList< MyString * > and MyList< Base *> are different classes that cannot be interconverted even if the contents can be.
    The second(outer) cast fails. Ok, so I bark up the wrong tree

    Why don't you take a step back and figure out why simply using MyList< Base * > everywhere isn't adequate? If all of the things you want to put in lists inherit from Base, then you can always construct lists containing any of the inherited class pointers. You can even mix list content pointers if you want. You pass MyList< Base * > pointers everywhere, and do your dynamic casting on the pointers in the list, not the list itself.

    I don't know what you intend to do with your list contents, but if you are clever with the interface you design for Base, you may not have to do any type casting at all. A virtual function in Base, reimplemented in each derived class, could be called as you iterate over the list. Because it is virtual, the compiler will cause the appropriate derived class method to be executed. So a virtual Base:: doSomething() method executed on a list of MyString pointers actually calls MyString:: doSomething().
    Yes I thought about it, but I like the existing solution. I know you think it's a bit confusing, and not the best style, but I think it's very flexibly and I have to do the casting just in the methods of the interface-class. So all other classes are able to call the remote-procedure-calls via the interface-instance and get what they expect. The only last element of uncertainty is the casting-issue. I saw implementations which use c-style casts[(MyList<MyString*>) createMyList()], which worked for whatever reason, but using c-style casting in a c++ app is like using a prybar. So I thought about static_cast, which worked (You explained why and I read the docs about casting). Maybe I should use static_cast finally. If I use it in the interface-class, I'm hundred percent sure, that the casting pointer holds the expected pointer, so it should be safe enough, shouldn't it?

    By all means, I'm thankful for your help and input.
    Last edited by QtCrawler; 15th December 2015 at 09:38.

  13. #11
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Is the down casting right, and why dynamic_cast fails?

    If I use it in the interface-class, I'm hundred percent sure, that the casting pointer holds the expected pointer, so it should be safe enough, shouldn't it?
    If you are the only one who will ever use your code, and if you are always sure that what you are using a static_cast for is what you think it should be, it will be safe.

    The problem with static_cast in code that others might use is that they may not realize what is happening "under the hood" and might pass the wrong thing into a function. Because static_cast is a prybar (more like a sledgehammer) it will always work, but could lead to crashes and data corruption which are hard to diagnose. You step into a method, and none of the values in the data structure make any sense because the static_cast was done on the wrong data type.

    It is best avoided in favor of a class structure that requires no casting of any sort.

Similar Threads

  1. help dynamic_cast
    By giorgik in forum Qt Programming
    Replies: 12
    Last Post: 5th October 2012, 08:29
  2. qobject_cast vs dynamic_cast
    By mike_c in forum Qt Programming
    Replies: 5
    Last Post: 19th April 2010, 18:51
  3. dynamic_cast not working
    By kloffy in forum Newbie
    Replies: 2
    Last Post: 11th October 2007, 23:07
  4. dynamic_cast and templates
    By KShots in forum General Programming
    Replies: 7
    Last Post: 7th August 2007, 20:01
  5. Problem with dynamic_cast
    By vratojr in forum General Programming
    Replies: 7
    Last Post: 12th April 2006, 13:45

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.