CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 13 of 13
  1. #1
    Join Date
    Sep 2001
    Location
    Turkey
    Posts
    173

    multi-inheritance & cast

    Hi,

    I have a strange problem.
    Firstly let me figure out my classes.


    class IQueable //abstract class, i.e. interface
    {
    virtual int GetPriority() = 0; //pure virtual fnc.
    };


    class CQueue()//real class; implemented
    {
    void Enqueue( IQueable* apElem );
    IQueable* Dequeue( IQueable* apElem );
    ...
    };


    class CBaseTask //real base class; implemented
    {
    int GetStatus();
    void SetStatus( int anStat );
    int m_nStatus; //default is initialized 0.
    };

    //real multi-inherited class; implemented
    class CDerivedQueableTask : public CBaseTask, public IQueable
    {
    virtual int GetPriority(){ return 2; };
    ...
    }

    void main()
    {
    CQueue* pQueue = new CQueue();
    CDerivedQueableTask* pTask = new CDerivedQueableTask();
    pTask->SetStatus( 1 );
    //the above task is deriven from IQueable
    pQueue->Enqueue( pTask );

    CBaseTask* pBT = (CBaseTask*)pQueue->Dequeue();
    //the above base is not deriven from IQueable,
    //but I am sure that it is CDerivedQueableTask which implemets IQueable.
    //it is just a few line above...
    pBT->GetStatus(); //returns some meaningless value; e.g. 701356
    }


    As you see if I cast the dequeued object( CDerivedQueableTask ) to CTask, I get inconsistent result.
    If I change it to the following, it works!
    CDerivedQueableTask* pTask = (CDerivedQueableTask*)pQueue->Dequeue();


    What may be the problem ?
    Last edited by the one; November 13th, 2003 at 08:29 AM.

  2. #2
    Join Date
    Nov 2003
    Location
    Belgium
    Posts
    8,150
    I could first try it with the dynamic_cast operator instead of the C-style casting.
    So something like this:

    Code:
    CBaseTask* pBT = dynamic_cast<CBaseTask*>(pQueue->Dequeue());
    and see if that works.
    Marc Gregoire - NuonSoft (http://www.nuonsoft.com)
    My Blog
    Wallpaper Cycler 3.5.0.97

    Author of Professional C++, 4th Edition by Wiley/Wrox (includes C++17 features)
    ISBN: 978-1-119-42130-6
    [ http://www.facebook.com/professionalcpp ]

  3. #3
    Join Date
    Sep 2001
    Location
    Turkey
    Posts
    173
    it is more dangerous.. it works wrong and whenever I want to touch my exe it asserts..

    please note that the above code is just a toy-version of my app.
    but it is one-to-one regarding the sckeleton

  4. #4
    Join Date
    Nov 2003
    Location
    Belgium
    Posts
    8,150
    mm, i had a second look at your code and the Dequeu function returs a IQueable* object. CBaseTask does not inherit from IQueable, so i think that's the problem.

    Why don't you let CBaseTask derive from IQueable?
    Marc Gregoire - NuonSoft (http://www.nuonsoft.com)
    My Blog
    Wallpaper Cycler 3.5.0.97

    Author of Professional C++, 4th Edition by Wiley/Wrox (includes C++17 features)
    ISBN: 978-1-119-42130-6
    [ http://www.facebook.com/professionalcpp ]

  5. #5
    Join Date
    Sep 2001
    Location
    Turkey
    Posts
    173
    Firstly thanks for your replies..
    CBaseTask does not inherit from IQueable
    But we know that it is actually a IQueable. Because it is created as CDerivedQueableTask....
    Why don't you let CBaseTask derive from IQueable?
    As a character, CTask doesn't have to be queued. But CDerivedQueableTask should. These are just dummy classes I wrapped here, I mean I couldn't make CTask as IQueable, it violets me in many where... ( you know, I couldn't explaine whole the project here )

    Any more help?

  6. #6
    Join Date
    Sep 2003
    Location
    Forever Gone... For Now...
    Posts
    1,515
    Originally posted by the one
    it is more dangerous.. it works wrong and whenever I want to touch my exe it asserts..
    It does this because you are trying to cast something to a non-related type. It's not more dangerous, it is safer because it is preventing you from doing something that you shouldn't. I'm guessing that dynamic_cast is returning NULL, and this is causing you problems.
    MSDN for dynamic_cast:
    When you use dynamic_cast < type-id > ( expression ), if expression cannot be safely converted to type type-id, the run-time check causes the cast to fail. For example:
    Code:
    class A { ... };
    
    class B { ... };
    
    void f()
    {
       A* pa = new A;
       B* pb = dynamic_cast<B*>(pa);      // fails, not safe; 
                                        // B not derived from A
       ...
    }
    The value of a failed cast to pointer type is the null pointer.
    Thought for the day/week/month/year:
    Windows System Error 4006:
    Replication with a nonconfigured partner is not allowed.

  7. #7
    Join Date
    Sep 2001
    Location
    Turkey
    Posts
    173
    My original code is not dynamic_cast. It is pure casting.. ( C type )
    (CTask*)pQueue->Dequeue();

  8. #8
    Join Date
    Sep 2003
    Location
    Forever Gone... For Now...
    Posts
    1,515
    Originally posted by the one
    My original code is not dynamic_cast. It is pure casting.. ( C type )
    (CTask*)pQueue->Dequeue();
    Right. This is dangerous for the reason(s) outlined in my previous post. dynamic_cast is safer because it isn't a "force cast" - it fails if expression cannot be converted to the type speficied by typeid. You are trying to do something unsafe with "(CTask*)pQueue->Dequeue();" (or whatever the cast of the day appears to be), and you are seeing the results with your "meaningless value".
    Thought for the day/week/month/year:
    Windows System Error 4006:
    Replication with a nonconfigured partner is not allowed.

  9. #9
    Join Date
    Sep 2001
    Location
    Turkey
    Posts
    173
    but why doesn't 'force cast' cast it correctly ? They are valid object as you see..

  10. #10
    Join Date
    Sep 2002
    Location
    14° 39'19.65"N / 121° 1'44.34"E
    Posts
    9,815
    Originally posted by the one
    but why doesn't 'force cast' cast it correctly ? They are valid object as you see..
    Valid objects, but not derived from a common base class. You can't just force an object to being of another type. You can only cast upward (always)or downward (sometimes) in the class hierarchy.

  11. #11
    Join Date
    Sep 2003
    Location
    Forever Gone... For Now...
    Posts
    1,515
    Originally posted by the one
    but why doesn't 'force cast' cast it correctly ? They are valid object as you see..
    Since you're changing classes (What's a CTask*? It's not referenced/defined in your original post...), it may be difficult to get on common ground, but going off of:
    Code:
    CBaseTask* pBT = (CBaseTask*)pQueue->Dequeue();
    pBT->GetStatus();
    from the original post...
    pQueue is of type CQueue*.
    CQueue::Dequeue returns an IQueable*.
    CBaseTask does not derive from IQueable. You are trying to force a CBaseTask to be an IQueable, and the types are not related to each other. A force cast does cast it "correctly" in the sense that you can call methods on the object. But this behavior is undefined. Depending on what the "GetStatus" method does, you could have an access violation immediately, or not see anything bad happen at all (aside from the "meaningless value").

    Don't do what you're trying to do.

    Code:
    //the above base is not deriven from IQueable, 
    //but I am sure that it is CDerivedQueableTask which implemets IQueable.
    Then change the code to:
    Code:
    CDerivedQueableTask* pDQT = dynamic_cast< CDerivedQueableTask* >( pQueue->Dequeue() );
    Or make CBaseTask inherit from IQueable.
    Thought for the day/week/month/year:
    Windows System Error 4006:
    Replication with a nonconfigured partner is not allowed.

  12. #12
    Join Date
    Mar 2002
    Location
    Croatia
    Posts
    275
    [QUOTE]Originally posted by the one
    it is more dangerous.. it works wrong and whenever I want to touch my exe it asserts..

    I think that is the point.
    dynamic_cast is not dangerous, it just don't allow you to cast something that is not possible.
    So, if you apply C-style cast, you may become garbage.
    dynamic_cast <> will return NULL instead, so you can test your returned pointer and find out if it is valid or not.

    I think the problem is in the
    class CDerivedQueableTask : public CBaseTask, public IQueable
    that inherits from two base-classes.
    It's hard to describe on this piece of code, but CBaseTask and IQueable, although both are base classes for CDerivedQueableTask, one do not know about another, so cast fails.
    dynamic_cast shows you the problem, you can't ignore it.

  13. #13
    Join Date
    Sep 2001
    Location
    Turkey
    Posts
    173
    Thanks..
    I'will regard these.
    I may refine my design..

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured