what is side-cast or cross-cast in Dynamic_cast in C++

后端 未结 2 1305
伪装坚强ぢ
伪装坚强ぢ 2020-12-19 04:57

What is side-cast/cross-cast in Dynamic_cast in C++. Can someone explain with an example?

#include 
using namespac         


        
相关标签:
2条回答
  • 2020-12-19 05:07

    The terms are pretty much explained in the comments, so I'm bundling that in my answer. But I think it is important to provide source code that shows the behavior of the code, since that provided by the asker only regards whether the crosscast compiles.

    Assuming this inheritance tree (the dreaded diamond):

            BaseClass
           /         \
          V           V
       Left          Right
           \        /
            V      V
           MostDerived
    

    Crosscast

    A crosscast or sidecast is when dynamic_cast(pRight) returns a Left* that properly behaves as a Left*. This happens when pRight points to a MostDerived object. Crosscasts only work with dynamic_cast, not reinterpret_cast or static_cast.

    Downcasting and Upcasting

    Downcast is casting from a Right* to a MostDerived*, which may fail. When it could fail, this should be done with a dynamic_cast, which sets the result to nullptr to signal failure. A common pattern is to have a dynamic_cast in debug, but to use a faster static_cast in the corresponding release code, as in:

    #ifdef NDEBUG
    return static_cast<MostDerived*>(input);
    #else
    auto p = dynamic_cast<MostDerived*>(input);
    assert(p != nullptr && "Unable to cast input to MostDerived*");
    return p; 
    #endif
    

    Upcasting is done implicitly when you pass a MostDerived* where any of the base classes is expected. This succeeds because MostDerived* is always a Right*, Left* and BaseClass*. However, because of the dreaded diamond, casting a MostDerived* to BaseClass* directly is ambiguous and results in a compiler error.

    So, in order to get a BaseClass* from a MostDerived*, we must first cast to Left* or Right* through an implicit upcast. The resulting Left* or Right* can be cast to the other side with a crosscast by using dynamic_cast. If using static_cast, the behaviour of the resulting pointer is incorrect when casting to Right*. This is due to the order that they are specified in MostDerived. This is because static cast does not change the pointer address, and therefore does not use the new vtable to resolve function calls.

    For this behaviour, it does not matter whether virtual inheritance is specified.

    The term crosscast is used in The C++ Programming Language, Fourth Edition by Bjarne Stroustrup, while sidecast is mentioned in point 5b of cppreference's explanation on dynamic_cast.

    The following source code prints the strange behaviour of a Right* that was static_cast from Left*, and therefore still behaves as a Left*. Note again that the converse is not the case, static_cast works fine from Right* to Left*.

    #include <iostream>
    
    struct BaseClass { virtual const char * behave() = 0; };
    struct Left : BaseClass { virtual const char * behave() { return "Left"; } };
    struct Right : BaseClass { virtual const char * behave() { return "Right"; } };
    struct MostDerived : Left, Right { };
    
    int main()
    {
        MostDerived * mostDerived = new MostDerived();
        // implicit upcast through the diamond results in a compile-time error, ambiguous:
        // BaseClass * baseClass = mostDerived;
        Left * left = mostDerived;
        BaseClass * baseClassThroughLeft = left; // or, equivalently:
        // BaseClass * baseClassThroughLeft = reinterpret_cast<Left*>(mostDerived);
        Right * right = mostDerived;
        BaseClass * baseClassThroughRight = left;
    
        // this is of course ambiguous and does not compile
        //std::cout << mostDerived->behave() << std::endl;
    
        // note, only the right has a pointer value of 8 more
        // the two BaseClass pointers point to the same as left,
        // as does mostDerived
        std::cout << "left:  " << left << std::endl << "right: " << right << std::endl 
                  << mostDerived << std::endl << baseClassThroughRight << std::endl 
                  << baseClassThroughLeft << std::endl;
    
        std::cout << "Cast Left BaseClass * expression to Right *:" << std::endl;
        std::cout << "with static_cast, behaves as " 
                  << static_cast<Right *>(baseClassThroughLeft)->behave() 
                  << " at addr: " << static_cast<Right *>(baseClassThroughLeft) << std::endl;
        std::cout << "with dynamic_cast, behaves as "
                  << dynamic_cast<Right *>(baseClassThroughLeft)->behave() 
                  << " at addr: " << dynamic_cast<Right *>(baseClassThroughLeft) << std::endl;
    
        std::cout << "Cast Right BaseClass * expression to Left *:" << std::endl;
        std::cout << "with static_cast, behaves as " 
                  << static_cast<Left *>(baseClassThroughRight)->behave() 
                  << " at addr: " << static_cast<Left *>(baseClassThroughRight) << std::endl;
        std::cout << "with dynamic_cast, behaves as "
                  << dynamic_cast<Left *>(baseClassThroughRight)->behave() 
                  << " at addr: " << dynamic_cast<Left *>(baseClassThroughRight) << std::endl;
    
        delete mostDerived;
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-19 05:24

    I think this is a better answer for my question, not sure

    #include <iostream>
    using namespace std;
    class A
    {
        public:
    virtual ~A(){}  
    };
    class B: virtual public A
    {
    
    };
    class C:virtual public A
    {
    };
    
    class D:public B,public C
    {
    
    };
    int main() {
        // your code goes here
        D d;
        C*c= &d;
        //B*b = static_cast<B*>(c);//--cross cast using static cast gives compiler error
        D*dd = dynamic_cast<D*>(c);
        B*b = dynamic_cast<B*>(c);//--cross cast using dynamic cast succeeds
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题