Thread: Cast directly between baseclasses of an object?

  1. #1
    Registered User
    Join Date
    Jul 2013
    Posts
    2

    Question Cast directly between baseclasses of an object?

    I've got two classes, which are both derived from the same two baseclasses.
    Here's a representation of the actual code:


    Code:
    #include <vector>
    class BaseClassA
    {
    };
    
    
    class BaseClassB
    {
    };
    
    
    class TestClassX
        : public BaseClassA,
        public BaseClassB
    {
    };
    
    
    class TestClassY
        : public BaseClassA,
        public BaseClassB
    {
    };
    
    
    int main(int argc,char *argv[])
    {
        TestClassX *x = new TestClassX;
        TestClassY *y = new TestClassY;
        std::vector<BaseClassA*> v;
        v.push_back(x);
        v.push_back(y);
        for(int i=0;i<v.size();i++)
        {
            BaseClassA *a = v[i];
            //BaseClassB *b = static_cast<BaseClassB*>(a); // Does not work
            
            delete a;
        }
        return 0;
    }
    (As I said, just a representation)

    Basically, I'd like to know if it is possible to cast directly from a BaseClassA pointer to a BaseClassB pointer, without casting to the child class first.
    I'm aware that situation like this should be avoided, nonetheless I'd like to know if there's a solution for this.

  2. #2
    Registered User antred's Avatar
    Join Date
    Apr 2012
    Location
    Germany
    Posts
    257
    As far as the compiler is concerned BaseClassA and BaseClassB are totally unrelated, so no.

  3. #3
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Actually, you can cast directly between them in this case.
    However you can only do it using dynamic_cast!
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  4. #4
    Registered User antred's Avatar
    Join Date
    Apr 2012
    Location
    Germany
    Posts
    257
    Quote Originally Posted by iMalc View Post
    Actually, you can cast directly between them in this case.
    However you can only do it using dynamic_cast!
    Are you sure? I don't have a compiler on this computer to try it out, but it seems to me that dynamic_cast should not be able to cast between types that are not related in any way whatsoever.

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    This will invoke a runtime cost, though (using dynamic_cast), just so you know.

    EDIT: VS and clang seems to disagree:
    Code:
    class BaseClassA
    {
    };
     
     
    class BaseClassB
    {
    };
     
     
    class TestClassX
        : public BaseClassA,
        public BaseClassB
    {
    };
     
     
    class TestClassY
        : public BaseClassA,
        public BaseClassB
    {
    };
    
    int main()
    {
    	TestClassX A;
    	TestClassX* pA = &A;
    	TestClassY* pB = dynamic_cast<TestClassY*>(pA);
    }
    Temp.cpp:87:19: error: 'TestClassX' is not polymorphic
    TestClassY* pB = dynamic_cast<TestClassY*>(pA);

    EDIT2:
    If you add virtual functions to the base classes, it will compile.
    Last edited by Elysia; 07-01-2013 at 07:08 PM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #6
    Registered User antred's Avatar
    Join Date
    Apr 2012
    Location
    Germany
    Posts
    257
    Well, I'll be damned, give both base classes a virtual test method, and it really does compile! Did not know that ...

    Compile and Execute C++ online

  7. #7
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    If you add virtual functions to the base classes, it will compile.
    O_o

    You still have a bug.

    That would always be null.

    Soma

    Code:
    class BaseClassA
    {
        virtual void doSomething(){};
    };
    
    
    class BaseClassB
    {
        virtual void doSomething(){};
    };
    
    
    class TestClassX
        : public BaseClassA,
        public BaseClassB
    {
    };
    
    
    class TestClassY
        : public BaseClassA,
        public BaseClassB
    {
    };
    
    int main()
    {
        TestClassX A;
        BaseClassA* pA = &A;
        BaseClassB* pB = dynamic_cast<BaseClassB*>(pA);
    }
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  8. #8
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    I happen to know because I ran into it for the first time within the last couple of weeks.
    Although it was a colleague of mine who needed such a thing, it was exactly the same multiple inherritance case as is shown here. The derived class used multiple inherritance and there was a need to go from one base class pointer to the other, when the object was known to be of the type that was derived from both bases.
    dynamic_cast worked and did not return NULL, and the code actually worked, doing what it should do. This was with VS2012. I may have to look into the actual code I guess.

    Oh I see, Elysia's example was wrong, casting it to the wrong type. Phantomotap's post has the fix. TestClassY really just muddies the situation, and is not needed in a mock example.
    Last edited by iMalc; 07-02-2013 at 12:47 AM.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  9. #9
    Registered User antred's Avatar
    Join Date
    Apr 2012
    Location
    Germany
    Posts
    257
    So this is actually a somewhat contrived case of runtime duck typing in C++? Class A and class B may not actually be related to each other but so long as they have a compatible interface of virtual methods, the cast will work?


    EDIT: The following seems to compile, even without there being any inheritance at play at all.

    Code:
    class BaseClassA
    {
        virtual void test() {}
    }; 
     
    class BaseClassB
    {
        virtual void test() {}
    };
    
    int main()
    {
        BaseClassA* const a = new BaseClassA;
        BaseClassB* const b = dynamic_cast < BaseClassB* > ( a ); // Does not work
             
        delete a;
        
        return 0;
    }
    EDIT #2: Oh well, on closer inspection, the cast actually fails.

    Code:
    #include <iostream>
    
    class BaseClassA
    {
    public:
        virtual void test() const
        {
            std::cout << "BaseClassA::test\n";
        }
    }; 
     
    class BaseClassB
    {
    public:
        virtual void test() const
        {
            std::cout << "BaseClassB::test\n";
        }
    };
    
    int main()
    {
        const BaseClassA* const a = new BaseClassA;
        const BaseClassB* const b = dynamic_cast < const BaseClassB* > ( a );
        
        if ( ! b )
        {
            std::cerr << "Cast failed!\n";
            return 1;
        }
        
        b->test();
             
        delete a;
        
        return 0;
    }
    Last edited by antred; 07-02-2013 at 03:44 AM.

  10. #10
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    So this is actually a somewhat contrived case of runtime duck typing in C++?
    O_o

    No. This is inheritance based polymorphisms.

    You can get something like "duck typing" with templates if you squint your eyes really hard.

    Class A and class B may not actually be related to each other but so long as they have a compatible interface of virtual methods, the cast will work?
    No.

    This works regardless of the interfaces of the base classes where the interface of each base is unrelated. They can be the same obviously, but you'll have errors regarding the which to choose. They should actually be different for the sake of example.

    You see, `BaseClassA' and `BaseClassB' are indeed unrelated, but `TestClassX' is both a `BaseClassA' and a `BaseClassB'. (Actually, `TestClassY' is also both a `BaseClassA' and a `BaseClassB'.) By being both a `BaseClassA' and a `BaseClassB' it is only natural that a `TestClassX' reference be useable as a reference to both `BaseClassA' and `BaseClassB'.

    1): Change `BaseClassA::doSomething'/`BaseClassB::doSomething' to `BaseClassA::doSomethingA' and `BaseClassB::doSomethingB' respectively.

    2): Add some code within both functions showing the label.

    3): Use both functions relative to the casting from and of a `TestClassX' and `TestClassY' instance.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  11. #11
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    I'm afraid not antred. You've been misled by Elysia's broken example.
    It's simply a case of you have an object of type "derived" which derives from both "base1" and "base2" then if you have a pointer to the "base2" part of the "derived" object, then we know that the object also inherrits from the "base2" type. Thus it contains all the members for a "base2" object as well and we can legimately cast from "base1" to "base2", but only because it is of type "derived".

    If we had a list of base1 pointers, and some of those were actual instance of derived, but some were instances of base1 only, then only the instances of derived would be able to be dynamically casted to base2 pointers successfully. The other items, which do not contain a base2 as well through their inherritance, would give NULL upon attempting to do the dynamic_cast.

    As this implies, there is no way to avoid the runtime cost of the dynamic_cast either, given that the object may or may not also be derived from the target type, and if it does, then it most certainly will not exist at the exact same address as the other base type, and so involves at least a pointer addition or subtraction.

    Or to put it another way, this is a "give me your sister's mobile number" kind of cast.
    Last edited by iMalc; 07-02-2013 at 01:30 PM.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. pass array directly to new object
    By a.mlw.walker in forum C++ Programming
    Replies: 3
    Last Post: 06-14-2013, 03:03 PM
  2. Streaming directly between streams
    By cunnus88 in forum C++ Programming
    Replies: 13
    Last Post: 10-10-2006, 10:24 PM
  3. can copy directly???
    By nurulhafiz in forum C Programming
    Replies: 4
    Last Post: 09-26-2006, 02:09 PM
  4. Inputting directly into memory
    By manwhoonlyeats in forum C Programming
    Replies: 5
    Last Post: 12-10-2002, 08:20 AM
  5. reinterpret_cast, C-style cast or function-style cast
    By blight2c in forum C++ Programming
    Replies: 3
    Last Post: 05-14-2002, 10:07 PM

Tags for this Thread