CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12
  1. #1
    Join Date
    Aug 2009
    Posts
    11

    Function overloading

    Hi to everyone,
    I have a little problem with my classes but before describing the problem I wish to ask forgiveness if similar questions were made before. This forum is huge and I'm unsure what to search so my apologize if made another useless post.

    The problem is this one:

    I have an abstract class named Collision wich have a pure virtual method "collide" which get a Collision* in input. I also have two implementations: CollisionBox and CollisionSphere. Both of these class implement the "collide" method once for each kind of collision (Box to Box, Sphere to Sphere, Box to Sphere).

    Now the problem is: if I implement the "collide" method like these way (once in CollisionBox and then again in CollisionSphere):
    Code:
    bool CollideBox::collide(Collision* collident) {...}
    bool CollideBox::collide(CollisionBox* collident) {...}
    bool CollideBox::collide(CollisionSphere* collident) {...}
    I usually have a Collision* pointer to pass to these method so always the first method will be called unless I dynamic cast the pointer to the right class... for example if I do:
    Code:
    CollisionBox* box = new CollisionBox();
    Collision* generic = new CollisionBox();
    
    box->collide(generic);
    I will get the first method to be called but I wish the second one (collide(CollisionBox*) ) to be called.

    Now actually I had to put a brutal switch and many dynamic casts in the general method (collide(Collision*)) which cast the pointer and call again the (hopefully) right "collide" method.

    Is there any other non-brutal way or pattern to create these cross calls between the implementations of the classes? I'm going to add more classes and I cannot make so many method whenever I add, move or edit a class.

    Thank you for the answers. I hope I was clear enough to explain my problem, if not then tell me: I'll try to make a better explanation.

  2. #2
    GCDEF is offline Elite Member Power Poster
    Join Date
    Nov 2003
    Location
    Florida
    Posts
    12,635

    Re: Function overloading

    What happens if you do it the other way around? Make collide a virtual member of Collision and pass it a CollideBox as a parameter.

  3. #3
    Join Date
    Jun 2008
    Location
    Oregon, USA
    Posts
    63

    Re: Function overloading

    I've never seen anyone try to make overloaded functions with subclasses where the superclass was also used in an overloaded function. I think the easiest way to make this work is to get rid of either

    collide(Collision* collident)

    OR

    the other two methods.

    I don't see any other feasible solution.

  4. #4
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: Function overloading

    This sounds tailor-made for a double-dispatch solution. Perhaps not precisely the visitor pattern, but similar.

    First, you'll want to re-order your overloads so that the base class overload comes last. I don't know if that will make a difference, but I think it might. You want the others to be preferred when possible.

    Second, define the base class version like so:
    Code:
    bool CollideBox::collide(Collision* other)
    {
        other->collide(this);
    }
    Now, it make take two collide() calls to fully resolve what's going on, but you can be sure that each call will resolve exactly one base class pointer into its concrete type via the virtual function table.

    Unfortunately, even though each class derived from Collision must have the same implementation (above) in the generic case, I think you can't just write it once in the base class in this case. We're relying here on "this" being passed as the derived type, after all.

  5. #5
    Join Date
    Aug 2009
    Posts
    11

    Re: Function overloading

    First, thank you all for your answers.

    Quote Originally Posted by GCDEF View Post
    What happens if you do it the other way around? Make collide a virtual member of Collision and pass it a CollideBox as a parameter.
    What do you mean? I'm not sure to understand clearly. "collide" is virtual (pure, thought).


    Quote Originally Posted by Bluefox815 View Post
    I've never seen anyone try to make overloaded functions with subclasses where the superclass was also used in an overloaded function. I think the easiest way to make this work is to get rid of either

    collide(Collision* collident)

    OR

    the other two methods.

    I don't see any other feasible solution.
    Which others two methods? The ones I suggested? To dispatch everything in every subclass?


    Quote Originally Posted by Lindley View Post
    This sounds tailor-made for a double-dispatch solution. Perhaps not precisely the visitor pattern, but similar.

    First, you'll want to re-order your overloads so that the base class overload comes last. I don't know if that will make a difference, but I think it might. You want the others to be preferred when possible.

    Second, define the base class version like so:
    Code:
    bool CollideBox::collide(Collision* other)
    {
        other->collide(this);
    }
    Now, it make take two collide() calls to fully resolve what's going on, but you can be sure that each call will resolve exactly one base class pointer into its concrete type via the virtual function table.

    Unfortunately, even though each class derived from Collision must have the same implementation (above) in the generic case, I think you can't just write it once in the base class in this case. We're relying here on "this" being passed as the derived type, after all.
    This sounds a good idea but I'm unsure how to implement it correctly, in my tests this I've got only a infinite recurive calling to the same method... which lead to a stack overflow (and a big red warning from my firewall).


    Of course I could remove the responsability to check the collision from these classes and make another classe which dispatch the message correctly but (even if I think I'll have to do this way) I don't like it. First I have to move the responsabilities of the collision away from the collision classes and also I have to expose the internal method and/or data to this new class...
    I think I'll try to find another solutions, if possible.
    Last edited by BlueAngelTC; May 12th, 2010 at 09:58 AM. Reason: wrong tipinh

  6. #6
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: Function overloading

    Quote Originally Posted by BlueAngelTC View Post
    This sounds a good idea but I'm unsure how to implement it correctly, in my tests this I've got only a infinite recurive calling to the same method... which lead to a stack overflow (and a big red warning from my firewall).
    Then you probably didn't override collide(Collision* other) in each subclass as Lindley pointed out.
    Of course I could remove the responsability to check the collision from these classes and make another classe which dispatch the message correctly but (even if I think I'll have to do this way) I don't like it. First I have to move the responsabilities of the collision away from the collision classes and also I have to expose the internal method and/or data to this new class...
    In my opinion it would be better to keep the logic you are trying to implement out of these classes. The key characteristic is that you always need to know about two objects in order to evaluate a collision. That means that each class must know about each other class in your original design. So your argument of not having to expose internal data doesn't hold, because a CollisionBox needs to have access to a CollisionShpere (and all other types) anyway.

    I would use the collision classes to dispatch these calls to some sort of collision manager that has knowledge of all types. In the collision manager you can implement the logic for each pair of types. Much easier to manage if you ask me.
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  7. #7
    Join Date
    Aug 2009
    Posts
    11

    Re: Function overloading

    Quote Originally Posted by D_Drmmr View Post
    Then you probably didn't override collide(Collision* other) in each subclass as Lindley pointed out.
    I did it, the collide(Collision*) in every sub class and then in every sub class the othe methods:
    collide(CollisionBox*)
    collide(CollisionSphere*)


    Quote Originally Posted by D_Drmmr View Post
    In my opinion it would be better to keep the logic you are trying to implement out of these classes. The key characteristic is that you always need to know about two objects in order to evaluate a collision. That means that each class must know about each other class in your original design. So your argument of not having to expose internal data doesn't hold, because a CollisionBox needs to have access to a CollisionShpere (and all other types) anyway.
    This isn't necessary true: when I collide a box with a sphere I have to calculate a point and pass it to the sphere without expose the internal data of the box to the sphere.
    Anyway you are right: in other cases this could lead to expose data to the other implementations.

    I will solve my problem maybe this way but is there a solution for the problem as I described?

  8. #8
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: Function overloading

    Quote Originally Posted by BlueAngelTC View Post
    I will solve my problem maybe this way but is there a solution for the problem as I described?
    Can you provide a minimal complete example of the code that gives you infinite recursion?
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  9. #9
    Join Date
    Aug 2009
    Posts
    11

    Re: Function overloading

    Astratta.h
    Code:
    #ifndef ASTRATTA_H_
    #define ASTRATTA_H_
    class Astratta
    {
    public:
        Astratta();
        virtual ~Astratta();
    
        virtual void test(Astratta* test) { test->test(this); }
    };
    #endif /* ASTRATTA_H_ */
    BetaImpl.h
    Code:
    #ifndef BETAIMPL_H_
    #define BETAIMPL_H_
    
    #include "Astratta.h"
    class ImplOne;
    
    class BetaImpl : public Astratta
    {
    public:
        BetaImpl();
        virtual ~BetaImpl();
    
        void test(BetaImpl* boh);
        void test(ImplOne* boh);
        void test(Astratta* boh) { boh->test(this); }
        void arconte();
    };
    
    #endif /* BETAIMPL_H_ */
    BetaImpl.cpp
    Code:
    #include "BetaImpl.h"
    #include "ImplOne.h"
    #include <iostream>
    
    using std::cout;
    
    BetaImpl::BetaImpl()
    {
    }
    
    void BetaImpl::test(BetaImpl* boh)
    {
        cout << "Beta: BetaImpl.\n";
    }
    
    void BetaImpl::test(ImplOne* boh)
    {
        cout << "Beta: ImplOne.\n";
    
    
    BetaImpl::~BetaImpl()
    {
    }
    ImplOne.h
    Code:
    #ifndef IMPLONE_H_
    #define IMPLONE_H_
    
    #include "Astratta.h"
    class BetaImpl;
    
    class ImplOne : public Astratta
    {
    public:
        ImplOne();
        virtual ~ImplOne();
    
        void test(BetaImpl* boh);
        void test(ImplOne* boh);
        void test(Astratta* boh) { boh->test(this); }
    };
    
    #endif /* IMPLONE_H_ */
    ImplOne.cpp:
    Code:
    #include "ImplOne.h"
    #include "BetaImpl.h"
    #include <iostream>
    
    using std::cout;
    
    ImplOne::ImplOne()
    {
    }
    void ImplOne::test(BetaImpl* boh)
    {
        cout << "Impl: BetaImpl.\n";
    }
    
    void ImplOne::test(ImplOne* boh)
    {
        cout << "Impl: ImplOne.\n";
    }
    
    ImplOne::~ImplOne()
    {
    }
    main.cpp:
    Code:
    #include "Astratta.h"
    #include "BetaImpl.h"
    #include "ImplOne.h"
    
    BetaImpl* beta = new BetaImpl();
    ImplOne* alfa = new ImplOne();
    cout << "Alfa...\n";
    beta->test(alfa);
    cout << "Beta...\n";
    beta->test(beta);
    cout << "Gamma...\n";
    Astratta* astr = new ImplOne();
    beta->test(astr);  // <--- CRASH
    
    cout << "Salto!\n";
    delete beta;
    delete alfa;

  10. #10
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: Function overloading

    You need to provide (virtual) overloads of test for each derived class in Astratta. Else, it will always call the overload taking a Astratta*, because that is the only one available in the base class.
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  11. #11
    Join Date
    Aug 2009
    Posts
    11

    Re: Function overloading

    Do you mean I should include each of the derived class in the base class? In Astratta?

    This is too ugly. It goes against every good rule of programming.
    I will use another class as dispatcher instead.

    Thank you for your replies.
    Last edited by BlueAngelTC; May 12th, 2010 at 01:59 PM. Reason: wrong tiping again

  12. #12
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: Function overloading

    Yes, I'm not a fan of that aspect of the visitor pattern.

    However, using forward declarations it isn't *all* that bad....
    Code:
    class BetaImpl;
    class ImplOne;
    
    class Astratta
    {
    public:
        Astratta();
        virtual ~Astratta();
    
        virtual void test(BetaImpl *t) {}
        virtual void test(ImplOne *t) {}
        virtual void test(Astratta* test) = 0;
    };

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