CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 7 of 7
  1. #1
    Join Date
    Jan 2010
    Posts
    10

    Multiple virtuality

    Is it possible to make a virtual function behave differently based on the data it is given even if the latter is an abstract pointer and how?

    I tried making something like that, the function calls look good enough, but the implementation is simplistic. I'd rather not have a switch statement in every concrete class derived form BaseB.



    Code:
    #include <iostream>
    
    
    using namespace std;
    
    class BaseA
    {
        public:
        virtual char getType()=0;
    
    };
    
    class A1:public BaseA
    {
        public:
        char getType()
        {
            return 'a';
        }
    };
    
    class A2:public BaseA
    {
        public:
        char getType()
        {
            return 'b';
        }
    
    };
    
    class BaseB
    {
        public:
        virtual void use(BaseA*)=0;
    };
    
    
    
    class B1:public BaseB
    {
        public:
    
        void use(BaseA* basea)
        {
            switch(basea->getType())
            {
                case 'a':
                handle((A1*)basea);
                break;
                case 'b':
                handle((A2*)basea);
                break;
                default:
                break;
            }
        }
        void handle(A1* a1)
        {
            cout<<"B1 uses A1"<<endl;
        }
        void handle(A2* a2)
        {
            cout<<"B1 uses A2"<<endl;
        }
    };
    
    class B2:public BaseB
    {
        public:
        void use(BaseA* basea)
        {
            switch(basea->getType())
            {
                case 'a':
                handle((A1*)basea);
                break;
                default:
                break;
            }
        }
        void handle(A1* a1)
        {
            cout<<"B2 uses A1"<<endl;
        }
        void handle(A2* a2)
        {
            cout<<"B2 uses A2"<<endl;
        }
    };
    
    int main()
    {
    
        BaseA* baseA[2]={new A1, new A2};
        BaseB* baseB[2]={new B1, new B2};
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
                baseB[i]->use(baseA[j]);
    
        return 0;
    }
    Last edited by wasd; February 9th, 2011 at 03:03 PM.

  2. #2
    Join Date
    Mar 2001
    Posts
    2,529

    Re: Multiple virtuality

    Why would you want to do that? Polymorphism will handle that for you!

    Well I have seen it done with MFC and CObject, apparently when you derive from CObject you can get type info. I have seen case statements like that, but I personally believe C++ is designed to avoid just this sort of thing.
    ahoodin
    To keep the plot moving, that's why.

  3. #3
    Join Date
    Jan 2010
    Posts
    10

    Re: Multiple virtuality

    I don't know how to make the use() of BaseB act different depending on the data it is given. I want to make use() react differently if I pass it either A1* or A2* via BaseA*. Switch is the best I could come up with.

  4. #4
    Join Date
    Oct 2006
    Location
    Sweden
    Posts
    3,654

    Re: Multiple virtuality

    They already act differently, otherwise your call to getType wouldn't have worked.
    I.e. all you have to do is to declare the common interface for A1 and A2 in BaseA. Whenever a user (with knowledge of only BaseA) gets an object (of either A1 or A2) and calls a method the correct object will be called (just as getType is).
    Debugging is twice as hard as writing the code in the first place.
    Therefore, if you write the code as cleverly as possible, you are, by
    definition, not smart enough to debug it.
    - Brian W. Kernighan

    To enhance your chance's of getting an answer be sure to read
    http://www.codeguru.com/forum/announ...nouncementid=6
    and http://www.codeguru.com/forum/showthread.php?t=366302 before posting

    Refresh your memory on formatting tags here
    http://www.codeguru.com/forum/misc.php?do=bbcode

    Get your free MS compiler here
    https://visualstudio.microsoft.com/vs

  5. #5
    Join Date
    Jan 2010
    Posts
    10

    Re: Multiple virtuality

    Well yeah, but I ended up using switch(basea->getType()) to call the functions handle(A1*) or handle (A2*). I would like that use(BaseA*) would call the specific overloaded handle() without switch.

  6. #6
    Join Date
    Jan 2001
    Posts
    253

    Re: Multiple virtuality

    You can achieve this by using a double dispatch, which is often achieved using the Visitor pattern.

    One way of implementing this is as follows:

    Code:
    #include <iostream>
    
    using namespace std;
    
    class A1;
    class A2;
    
    struct AVisitor
    {
       virtual void Visit(A1*) = 0;
       virtual void Visit(A2*) = 0;
    };
    
    class BaseA
    {
    public:
       virtual void Accept(AVisitor& visitor) = 0;
    };
    
    class A1:public BaseA
    {
    public:
       virtual void Accept(AVisitor& visitor)
       {
          visitor.Visit(this);
       }
    };
    
    class A2:public BaseA
    {
    public:
       virtual void Accept(AVisitor& visitor)
       {
          visitor.Visit(this);
       }
    };
    
    class BaseB : public AVisitor
    {
    public:
       virtual void use(BaseA*)=0;
    };
    
    class B1:public BaseB
    {
    private:
       void Visit(A1* a1)
       {
          cout<<"B1 uses A1"<<endl;
       }
    
       void Visit(A2* a2)
       {
          cout<<"B1 uses A2"<<endl;
       }
    
    public:
       void use(BaseA* basea)
       {
          basea->Accept(*this);
       }
    };
    
    class B2:public BaseB
    {
    private:
       void Visit(A1* a1)
       {
          cout<<"B2 uses A1"<<endl;
       }
    
       void Visit(A2* a2)
       {
          cout<<"B2 uses A2"<<endl;
       }
    
    public:
       void use(BaseA* basea)
       {
          basea->Accept(*this);
       }
    };
    
    int main()
    {
       BaseA* baseA[2]={new A1, new A2};
       BaseB* baseB[2]={new B1, new B2};
       for(int i=0;i<2;i++)
          for(int j=0;j<2;j++)
             baseB[i]->use(baseA[j]);
    
       return 0;
    }
    This works by calling the virtual Accept function of the BaseA class (dispatching to the appropriate class derived from BaseA). The Accept function calls the Visit member of the visitor that has the matching BaseA derived parameter.

    I made the BaseB class derive from the AVisitor class since this is just a simple case. This shows how you can implement a double-dispatch. If you want to have multiple virtual routines in the BaseA classes which can be called from BaseB, you can separate the visitor implementation into its own class.

    Note that I removed the getType() member since it isn't needed anymore.

  7. #7
    Join Date
    Jan 2010
    Posts
    10

    Re: Multiple virtuality

    Interesting, thanks.

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