CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 11 of 11
  1. #1
    Join Date
    Jan 2009
    Location
    Salt Lake City, Utah
    Posts
    82

    Question Multi-inheritance Polymorphism

    Suppose my code is setup like this:
    Code:
    class A
    {
    };
    
    class B
    {
    };
    
    class C : A,B
    {
    };
    
    A* someFunction()
    {
        return (A*) new C;
    }
    Notice I've casted a C into an A. C inherits A, but also B. Is this safe to do if I still know what type it is and cast it back latter, or does multi-inheritance bring up problems with polymorphism? As a second part to my question, would it also be okay to cast from C to B? In other words, does their order in the inheritance area of C's class definition matter, or can you only revert to the first inherited class? Thanks in advance.

  2. #2
    Join Date
    Feb 2009
    Location
    India
    Posts
    444

    Re: Multi-inheritance Polymorphism

    This type of casting called upcasting is always safe.
    An object of C can be cast to either A or B.

    You should however use dynamic_cast 'cause it will check if the casting is valid.
    «_Superman
    I love work. It gives me something to do between weekends.

    Microsoft MVP (Visual C++)

  3. #3
    Join Date
    Jan 2008
    Location
    California, USA
    Posts
    822

    Re: Multi-inheritance Polymorphism

    Quote Originally Posted by Etherous View Post
    In other words, does their order in the inheritance area of C's class definition matter, or can you only revert to the first inherited class? Thanks in advance.
    Hello Etherous,
    that's a very good question (something I want to learn more)

    AFAIK,
    in a single hierarchical..did I spell that right? multiple inheritance,
    the placement of the list of the base classes and in order which they
    appear in the constructor list doesn't really matter.
    But,
    if it's more than one level,
    the order of constructing happens from the top most base class and to the horizontonal classes.
    so if A is at the top, B derives from A. C is at the same level as B, and D derives from B and C,
    the order of construction is A, B, C, D, and vice versa for the destructors.
    I fear that this could present a problem, along with the ambiguty issues.

    As for the "upcasting"
    you just can't get around slicing (can we?)
    this led me to believe at this point in my learning that
    if casting is needed in an inheritance,
    the chance is that there exists an alternative design where you could use compostion.
    To test this, I went over my old programming excercises and tried composition modeling,
    and viola! it worked great.

    hope this helps

  4. #4
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: Multi-inheritance Polymorphism

    Quote Originally Posted by Etherous
    Notice I've casted a C into an A.
    Actually, assuming that the example was changed such that public inheritance was used, an explicit cast would be unnecessary, since C is-a A:
    Code:
    class A
    {
    public:
        virtual ~A() {}
    };
    
    class B
    {
    public:
        virtual ~B() {}
    };
    
    class C : public A, public B
    {
    };
    
    A* someFunction()
    {
        return new C;
    }
    Quote Originally Posted by Etherous
    As a second part to my question, would it also be okay to cast from C to B?
    Yes, but again a C is-a B, so an explicit cast is unnecessary. (If you really did want to explicitly cast, static_cast will suffice.)

    Quote Originally Posted by _Superman_
    You should however use dynamic_cast 'cause it will check if the casting is valid.
    Yes, to cast from A* to the B*, or from A* to C*, or from B* to C* (though static_cast can be used for the latter two if we know for certain that the object pointed to is a C).

    Quote Originally Posted by potatoCode
    As for the "upcasting"
    you just can't get around slicing (can we?)
    Slicing does not happen here since the return type is a pointer.
    Last edited by laserlight; February 24th, 2009 at 06:23 AM.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  5. #5
    Join Date
    Jan 2009
    Location
    Salt Lake City, Utah
    Posts
    82

    Re: Multi-inheritance Polymorphism

    Wow. Thanks so much for all your replies. This really helps.

  6. #6
    Join Date
    Jan 2008
    Location
    California, USA
    Posts
    822

    Re: Multi-inheritance Polymorphism

    Quote Originally Posted by laserlight View Post
    Slicing does not happen here since the return type is a pointer.
    Hello laserlight, how are you buddy?
    You always bring out the best in me!!

    My understanding of the return (A*) new C; was that object C was first allocated then casted to A* which could only hold(allocated memory) the un-sliced part of C which is A. That tells me A was constructued "from" C, although A was not copy constructed from C which in turn makes me question myself...

    But I guess I had it all wrong including the new part.
    can you explain this a bit more and point out what I got it wrong?

    Thanks

  7. #7
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: Multi-inheritance Polymorphism

    Quote Originally Posted by potatoCode
    My understanding of the return (A*) new C; was that object C was first allocated then casted to A* which could only hold(allocated memory) the un-sliced part of C which is A.
    Let's simplify the example:
    Code:
    #include <iostream>
    
    class A
    {
    public:
        virtual void foo() const
        {
            std::cout << "A::foo" << std::endl;
        }
    
        virtual ~A() {}
    };
    
    class C : public A
    {
    public:
        virtual void foo() const
        {
            std::cout << "C::foo" << std::endl;
        }
    };
    
    A* someFunction()
    {
        return (A*)new C;
    }
    
    int main()
    {
        A* p = someFunction();
        p->foo();
        delete p;
    }
    If you are right, and the explicit C-style cast to A* sliced off the C part of the object, then we would expect the output to be A::foo. However, this is not the case, since the A pointer continues to point to the C object, so the virtual call causes C's version of foo() to be called. Let's take a look at an example where slicing occurs:
    Code:
    #include <iostream>
    
    class A
    {
    public:
        virtual void foo() const
        {
            std::cout << "A::foo" << std::endl;
        }
    
        virtual ~A() {}
    };
    
    class C : public A
    {
    public:
        virtual void foo() const
        {
            std::cout << "C::foo" << std::endl;
        }
    };
    
    A someFunction()
    {
        return C();
    }
    
    int main()
    {
        A x = someFunction();
        x.foo();
    }
    Here, someFunction() returns an A object, not an A pointer, so slicing occurs and there is no polymorphism as in the first example.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  8. #8
    Join Date
    Nov 2003
    Posts
    1,405

    Re: Multi-inheritance Polymorphism

    Quote Originally Posted by laserlight View Post
    (If you really did want to explicitly cast, static_cast will suffice.)
    No, static_cast won't suffice.

    An upcast is always type-safe. If you don't upcast explicitly the compiler will check that it's a valid upcast for you.

    But if you do upcast explicitly you shortcut the compiler's type checking and assume full responsibility for the cast yourself. And this includes that it works a runtime which requires you to put in a dynamic_cast.

  9. #9
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: Multi-inheritance Polymorphism

    Quote Originally Posted by _uj
    No, static_cast won't suffice.
    It will, if you "if you really did want to explicitly cast". My point is that if you know for certain that a downcast will succeed, then you can use static_cast, and thus it follows that since an upcast will always succeed, then if you are anal about an explicit cast even when it is of no use (or as you pointed out, when it can even be harmful), static_cast should be good enough for you.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  10. #10
    Join Date
    Jan 2008
    Location
    California, USA
    Posts
    822

    Re: Multi-inheritance Polymorphism

    Thanks laserlight, you are, once again, of course right!

    I did some testing on my own and found out that you are also right
    in saying that static cast will suffice.
    And I didn't know about the no need to explicitly cast
    because of an IS-A relationship either (why couldn't I imgaine it before!)

    few more question.
    Code:
    int main()
    {
        A* p = someFunction();
        p->foo();
    
        A* p2(0);
    
        C* ptr = static_cast<C*>(p2);
        ptr->hi();  // hi() is a simple method in C only
    
        delete p;
    }
    ptr in this code does call the hi() method in C,
    which for the sake of my sanity, shouldn't happen.
    I assume, this is only UB, correct?

    Q2. When I generally debug (gdb), I mostly watch variables, funtion arguments and
    keep my eyes on the address. Is this the right or nomral way of debugging?

    Q3. When do I need to watch CPU register and callstack?

    as always, thanks!

  11. #11
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: Multi-inheritance Polymorphism

    Quote Originally Posted by potatoCode
    ptr in this code does call the hi() method in C,
    which for the sake of my sanity, shouldn't happen.
    I assume, this is only UB, correct?
    Yes, since you are dereferencing a null pointer. It probably "works" because hi() say, does not access any of the member variables.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

Tags for this Thread

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