dcsimg
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 15 of 15

Thread: Factory Method

  1. #1
    Join Date
    Aug 2010
    Posts
    5

    Factory Method

    I'm trying to make class that will select the correct method depending on what class instance 'm pointing to, this is my example code.


    //=================================================================//
    class parent {};
    class child1 : public parent {};
    class child2 : public parent {};

    class factory
    {
    public:
    virtual std::string log(parent* p) { return "parent"; }
    virtual std::string log(child1* c) { return "child1"; }
    virtual std::string log(child2* c) { return "child2"; }
    };

    main()
    {
    factory* f = new factory();
    parent* p = new parent();
    parent* c1 = new child1();
    parent* c2 = new child2();
    /*
    * Theese three pointers are just a example,
    * what I have finally is a list of parent pointers
    * which points to different classes inheriting parent.
    */
    std:: cout << f->log(p) << std::endl; // I want this to write "parent"
    std:: cout << f->log(c1) << std::endl; // I want this to write "child1", but it writes parent
    std:: cout << f->log(c2) << std::endl; // I want this to write "child2", but it writes parent
    }
    //=================================================================//


    Is there any way for C++ to automatically figure out what class it is pointing to, in order to make the factory class call the right method?

    PS. Just to calrify, the goal isn't to write the correct text, but to call the right method in factory. DS.

  2. #2
    Join Date
    Jan 2009
    Posts
    1,689

    Re: Factory Method

    Nope, if you have a parent pointer, C++ only knows that it's a parent nothing about what child class it is. You need to redesign your code.

  3. #3
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Factory Method

    It looks more like you should make "log" a virtual member of parent/child. What you are trying to replicate is the exact behavior of polymorphism.

    If your "log" is meant to behave as a non-member virtual function, you can always get away with only one log(const parent*), and a dynamic_cast inside. Some would complain and advise against the use of dynamic_cast (I included), but it is just as good as writing a function for each and every type.

    To answer your question real quick though, C++ can't statically call the right function, because the type of parent* is parent*, no exceptions.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  4. #4
    Join Date
    Aug 2010
    Posts
    5

    Re: Factory Method

    What I want to do is a factory with methods like

    log(parent* p, child* c) {}
    log(parent* p1, parent* p2) {}

    And when you start to mix calsses like that, a virtual function won't do the job anymore.

    And what I want to avoid is a huge switch case with a enum for every subclass.

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

    Re: Factory Method

    Well then, in that case it looks like you need to read up on the Visitor Pattern. Basically, you arrange things so that multiple virtual function calls are made, each resolving the actual type of a single object, so that you can eventually call the correct overloaded method.

  6. #6
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Factory Method

    What you are looking for are multy-functions:
    http://www2.research.att.com/~bs/japanese2010.pdf page 6: Post C++0x future evolution
    EDIT: acutally, it isn't quite what you are looking for.

    Unfortunately, C++ does not actually have this. The only way to get what you want is to either rely on a polymorphic function inside parent (for example "getParentName" the log could call), or to do a huge dynamic_cast+switch.

    I can't think of other ways...

    EDIT: Yeah, the visitor looks like it can do it. Looks kind of overkill to me though, but I don't know the rest, or how many of these factory classes you have.
    Last edited by monarch_dodra; August 17th, 2010 at 10:02 AM.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  7. #7
    Join Date
    Aug 2010
    Posts
    5

    Re: Factory Method

    The visitor pattern seems interesting, if I send in a the visitor as a argument in a virtual function, I can the save away what class it is I'm using, might work, I'll be back when I work something out.

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

    Re: Factory Method

    The only problem with the visitor pattern is the high code overhead it requires. However, you may be able to mitigate some of that by leveraging the Curiously-recurring Template Pattern as well.

  9. #9
    Join Date
    Aug 2010
    Posts
    5

    Re: Factory Method

    Quote Originally Posted by monarch_dodra View Post
    What you are looking for are multy-functions:
    http://www2.research.att.com/~bs/japanese2010.pdf page 6: Post C++0x future evolution
    EDIT: acutally, it isn't quite what you are looking for.

    Unfortunately, C++ does not actually have this. The only way to get what you want is to either rely on a polymorphic function inside parent (for example "getParentName" the log could call), or to do a huge dynamic_cast+switch.

    I can't think of other ways...

    EDIT: Yeah, the visitor looks like it can do it. Looks kind of overkill to me though, but I don't know the rest, or how many of these factory classes you have.
    That is just plain evil...

    The visitor pattern works fine for single argument functions, but "multy-funtions" really makes it harder.

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

    Re: Factory Method

    Well, here's a question. Are your 2-argument functions symmetric? If f(A,B) == f(B,A) (including side effects, not just return value), then visitor is pretty easy to adapt. It's a bit harder if you need to maintain argument ordering.

  11. #11
    Join Date
    Aug 2010
    Posts
    5

    Re: Factory Method

    Quote Originally Posted by Lindley View Post
    The only problem with the visitor pattern is the high code overhead it requires. However, you may be able to mitigate some of that by leveraging the Curiously-recurring Template Pattern as well.
    It was easy to make the visitor pattern for single argument methods in the factory class, no overhead at all, just a few lines. But how do I make it work for multi argument methods in the factory class?

  12. #12
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Factory Method

    Quote Originally Posted by MrLogic View Post
    It was easy to make the visitor pattern for single argument methods in the factory class, no overhead at all, just a few lines. But how do I make it work for multi argument methods in the factory class?
    It mainly depends if your arguments are dependent on one-another, ie: if you can some how write

    Code:
    foo(A a, B b)
    {
        bar(a);
        baz(b);
    }
    Then it is very easy.

    If you need to have a behavior that depends on the couple A/B, then it is more difficult. If you stick to polymorphisms, you can have a form of two level polymorphims:

    Code:
    foo(A* a, B* b)
    {
        a->bar(b);
    }
    If you stick to visitor, I have no idea, but I have a fealing it involves a level1Visitor being visited by a level2Visitor.

    Good luck.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  13. #13
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Factory Method

    By the way, do you REALLY need mutlyfunctions, or are you just asking? I don't have an answer for you, but this paper (the one I was talking about) may have some information in the introduction EDIT: or the references.

    http://www2.research.att.com/~bs/multimethods.pdf

    But you may want to ask yourself if your problem really requires all this, or if a simple redesign will not solve it.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

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

    Re: Factory Method

    Let's say I have base class Base, and derived classes D1 and D2. I want to call the correct version of a free-standing realcompare() method:

    Code:
    bool realcompare(D1 *lhs, D1 *rhs);
    bool realcompare(D1 *lhs, D2 *rhs);
    bool realcompare(D2 *lhs, D1 *rhs);
    bool realcompare(D2 *lhs, D1 *rhs);
    For simplicity we'll assume it isn't useful to pass a Base* to realcompare().

    Then we can make these classes both visitors *and* visitees as such:
    Code:
    class D1;
    class D2;
    
    class Base
    {
        virtual bool compare(Base *) = 0;
        virtual bool compare(D1 *) = 0;
        virtual bool compare(D2 *) = 0;
        virtual ~Base() {}
    };
    
    class D1: public Base
    {
        bool compare(Base *b)
        {    return b->compare(this); // this is the magic  }
        bool compare(D1 *other)
        {    return realcompare(this, other);    }
        bool compare(D2 *other)
        {    return realcompare(this, other);    }
    };
    
    class D2: public Base
    {
        bool compare(Base *b)
        {    return b->compare(this); // this is the magic  }
        bool compare(D1 *other)
        {    return realcompare(this, other);    }
        bool compare(D2 *other)
        {    return realcompare(this, other);    }
    };
    Note, however, that it is not intuitive to control which object ends up on the left or right in the realcompare() call. Hopefully this doesn't matter, but there are probably ways to fix it if it does.

    One thing I *can* fix is the fact that D1 and D2 share identical code. No, you can't put that code in Base----it works because it's happening in the derived class, unfortunately. But the Curiously Recurring Template pattern *can* help us out here:

    Code:
    class D1;
    class D2;
    
    class Base
    {
        virtual bool compare(Base *) = 0;
        virtual bool compare(D1 *) = 0;
        virtual bool compare(D2 *) = 0;
        virtual ~Base() {}
    };
    
    template <typename T>
    class BaseCRTP: public Base
    {
        bool compare(Base *b)
        {    return b->compare(static_cast<T*>(this)); // this is the magic  }
        bool compare(D1 *other)
        {    return realcompare(static_cast<T*>(this), other);    }
        bool compare(D2 *other)
        {    return realcompare(static_cast<T*>(this), other);    }
        virtual ~BaseCRTP() {}
    };
    
    class D1: public BaseCRTP<D1>
    {
         // NOTHING needed!
    };
    
    class D2: public BaseCRTP<D2>
    {
        // NOTHING needed!
    };
    We can avoid writing *anything* related to the visitor pattern itself in the derived classes because in this case the actual work is done in the free-standing realcompare() function. If you wanted to do the actual work in, say, D1::compare(D2*), then you'd need to keep those concrete methods in the derived classes; but you could still put the version taking a Base* in the CRTP class, saving yourself some effort.
    Last edited by Lindley; August 17th, 2010 at 10:51 AM.

  15. #15
    Join Date
    Aug 2005
    Location
    San Diego, CA
    Posts
    1,054

    Question Re: Factory Method

    The original example makes it difficult to understand the question. Typically a factory is used to build things. What are you building exactly? I don't really understand the problem. The name of a function tends to imply certain things such as what the user expects the function to do. Looking at that example I haven't the slightest idea what that factory object is supposed to do. the point of run-time binding (polymorphism) is to reduce compile time dependencies so that users don't need to know the kind of object that they have. Therefore the original example raises all kinds of red flags that would indicate that an alternative design is needed. However it would be difficult to make a suggestion without understanding what the goals are.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width




On-Demand Webinars (sponsored)