Polymorphism (without virtual functions) with a method template.

Discussion in 'C++' started by Belebele, Dec 11, 2007.

  1. Belebele

    Belebele Guest

    Suppose that I want to write a (concrete) interface class (without
    virtual functions) to classes that contain a method template

    // --------------------------------------
    class Interface {
    public:
    template <typename Wrapped>
    Interface(Wrapped& );
    // wraps a reference to another object
    // that implements the method template

    template <typename T>
    bool foo(T ); // forwards the call to the wrapped object
    };
    // --------------------------------------

    and then use it:

    // --------------------------------------
    class Bar {
    public:
    template <typename T>
    bool foo(T );
    };

    ....
    Bar b;
    Interface i(b);
    // --------------------------------------


    The problem is that I don't know how to implement this. I know how to
    implement it without method templates (with table of function
    pointers).

    Any idea how to do it?

    Thanks.
     
    Belebele, Dec 11, 2007
    #1
    1. Advertising

  2. Belebele

    Ondra Holub Guest

    On 11 Pro, 13:58, Belebele <> wrote:
    > Suppose that I want to write a (concrete) interface class (without
    > virtual functions) to classes that contain a method template
    >
    > // --------------------------------------
    > class Interface {
    > public:
    > template <typename Wrapped>
    > Interface(Wrapped& );
    > // wraps a reference to another object
    > // that implements the method template
    >
    > template <typename T>
    > bool foo(T ); // forwards the call to the wrapped object};
    >
    > // --------------------------------------
    >
    > and then use it:
    >
    > // --------------------------------------
    > class Bar {
    > public:
    > template <typename T>
    > bool foo(T );
    >
    > };
    >
    > ...
    > Bar b;
    > Interface i(b);
    > // --------------------------------------
    >
    > The problem is that I don't know how to implement this. I know how to
    > implement it without method templates (with table of function
    > pointers).
    >
    > Any idea how to do it?
    >
    > Thanks.


    I am not sure if I understood exactly what you need. If you want to
    store value of some templated type, you have to make the whole class
    templated (because the Wrapped type and value must be accessible from
    constructor as well as from method foo).

    // --------------------------------------
    template<typename Wrapped>
    class Interface {
    public:
    Interface(Wrapped& w): w_(w) { }
    // wraps a reference to another object
    // that implements the method template

    template <typename T>
    bool foo(T& t) // forwards the call to the wrapped object
    {
    w_.foo(t);
    }

    private:
    Wrapped& w_;
    };

    // --------------------------------------

    and then use it:

    // --------------------------------------
    class Bar {
    public:
    template <typename T>
    bool foo(T );

    };

    ....
    Bar b;
    Interface<Bar> i(b);
    // --------------------------------------
     
    Ondra Holub, Dec 11, 2007
    #2
    1. Advertising

  3. Belebele

    Belebele Guest

    > I am not sure if I understood exactly what you need. If you want to
    > store value of some templated type, you have to make the whole class
    > templated


    That's not what I want. I want the Interface class to be a class, not
    a class template. That way, I could potentially assign to an object of
    the Interface class any object that implements the desired interface.
    That is:

    class B1 {
    public:
    template <typename T>
    void foo(T );
    };

    class B2 {
    public:
    template <typename T>
    void foo(T );
    };

    B1 b1;
    Interface i(b1);
    i.foo(1);

    B2 b2;
    i = b2;
    i.foo(1);


    This is simple to implement if the interface does not contain method
    templates. I am lost when method templates are involved.
     
    Belebele, Dec 11, 2007
    #3
  4. Belebele

    Ondra Holub Guest

    On 11 Pro, 20:58, Belebele <> wrote:
    > > I am not sure if I understood exactly what you need. If you want to
    > > store value of some templated type, you have to make the whole class
    > > templated

    >
    > That's not what I want. I want the Interface class to be a class, not
    > a class template. That way, I could potentially assign to an object of
    > the Interface class any object that implements the desired interface.
    > That is:
    >
    > class B1 {
    > public:
    > template <typename T>
    > void foo(T );
    >
    > };
    >
    > class B2 {
    > public:
    > template <typename T>
    > void foo(T );
    >
    > };
    >
    > B1 b1;
    > Interface i(b1);
    > i.foo(1);
    >
    > B2 b2;
    > i = b2;
    > i.foo(1);
    >
    > This is simple to implement if the interface does not contain method
    > templates. I am lost when method templates are involved.


    I think it is not possible. You have to store the reference to other
    class instance, so the referenced class would have to be derived from
    some common class. It is hard to combine template polymorphism and
    class polymorphism.
     
    Ondra Holub, Dec 11, 2007
    #4
  5. On Dec 11, 2:58 pm, Belebele <> wrote:

    I am including your original Interface class here for
    reference.

    > class Interface {
    > public:
    > template <typename Wrapped>
    > Interface(Wrapped& );
    > // wraps a reference to another object
    > // that implements the method template
    >
    > template <typename T>
    > bool foo(T ); // forwards the call to the wrapped
    > // object
    > };


    For Interface to be able to keep a reference to the wrapped
    object, it needs to store it somewhere. Therefore, it needs
    to have a member object of an arbitrary type, namely T.
    Conclusion: Interface needs to be a class template.

    > That's not what I want. I want the Interface class to be a
    > class, not a class template. That way, I could potentially
    > assign to an object of the Interface class any object that
    > implements the desired interface. That is:


    One does not prevent the other. Look again at the example you
    were given in http://tinyurl.com/2rppm8. It corresponds to the
    problem you are explaining.

    > class B1 {
    > public:
    > template <typename T>
    > void foo(T );
    >
    > };
    >
    > class B2 {
    > public:
    > template <typename T>
    > void foo(T );
    >
    > };
    >
    > B1 b1;
    > Interface i(b1);
    > i.foo(1);
    >
    > B2 b2;
    > i = b2;
    > i.foo(1);
    >
    > This is simple to implement if the interface does not
    > contain method templates. I am lost when method templates
    > are involved.


    I don't see how this can be "simple to implement", except by
    using function pointers, which is not particularily simple,
    safe or fun to play with.

    You have two important requirements:

    1) Wrapped classes do not derive from a common base class.
    Therefore, you need the wrapper class to be templated.

    2) Some member functions in the wrapped classes are templated.
    Therefore, you need the wrapper class to have as many
    templated member functions.

    --
    Jonathan Mcdougall
     
    Jonathan Mcdougall, Dec 11, 2007
    #5
  6. Belebele

    Belebele Guest

    > I don't see how this can be "simple to implement", except by
    > using function pointers, which is not particularily simple,
    > safe or fun to play with.


    See Listing 1 on http://www.ddj.com/cpp/184401848 Yep, function
    pointers to the rescue. Nothing really too extraordinary.

    The method template requirement is what puzzles me.

    I would prefer not having to force the Wrapped objects to derive (in
    my case artificially) from a base class.
     
    Belebele, Dec 11, 2007
    #6
  7. On Dec 11, 5:48 pm, Belebele <> wrote:
    > > I don't see how this can be "simple to implement",
    > > except by using function pointers, which is not
    > > particularily simple, safe or fun to play with.

    >
    > See Listing 1 on http://www.ddj.com/cpp/184401848. Yep,
    > function pointers to the rescue. Nothing really too
    > extraordinary.


    I copy the listing (with some corrections) for the sake of the
    discussion:

    # include <iostream>

    struct AbcFuBar
    {
    virtual ~AbcFuBar()
    {
    }

    virtual void FuBar() = 0;
    };

    struct BaseFuBar : public AbcFuBar
    {
    void FuBar()
    {
    std::cout << "BaseFuBar";
    }
    };

    struct DerivedFuBar : public BaseFuBar
    {
    void FuBar()
    {
    std::cout << "DerivedFuBar";
    }
    };

    int main()
    {
    DerivedFuBar d;
    BaseFuBar& b = d;
    AbcFuBar& a = b;
    a.FuBar(); // output DerivedFuBar
    }

    This example does not correspond to your original post. It
    only demonstrates the use of inheritance and virtual
    functions.

    > The method template requirement is what puzzles me.
    >
    > I would prefer not having to force the Wrapped objects
    > to derive (in my case artificially) from a base class.


    Basically, you need templates if you don't have a base class.
    Otherwise, what will be the type of the member object of your
    "Interface" class?

    class wrapper
    {
    public:
    template <class T>
    wrapper(T& t)
    : t_(t)
    {
    }

    private
    ??? t_;
    };

    Note that you cannot replace ??? by T, since it only exists in
    the constructor. To do this, make wrapper a template:

    template <class T>
    class wrapper
    {
    public:
    wrapper(T& t)
    : t_(t)
    {
    }

    private:
    T t_;
    };

    in which case the constructor does not need to be templated
    anymore (unless it should accept things that are not Ts).

    Now, if you want to call member functions on the wrapped
    oject, you need to know the function names along with the type
    and numbers of parameters they take.

    template <class T>
    class wrapper
    {
    public:
    wrapper(T& t)
    : t_(t)
    {
    }

    void f(int i)
    {
    t_.f(i);
    }

    private:
    T t_;
    };

    class bar
    {
    public:
    void f(int i)
    {
    }
    };

    int main()
    {
    bar b;
    wrapper<bar> w(b);

    w.f(0);
    }

    To remove the "hardcoded" type information in f(), you can use
    templates:

    template <class T>
    class wrapper
    {
    public:
    wrapper(T& t)
    : t_(t)
    {
    }

    template <class P1>
    void f(P1 p1)
    {
    t_.f(p1);
    }

    private:
    T t_;
    };

    --
    Jonathan Mcdougall
     
    Jonathan Mcdougall, Dec 12, 2007
    #7
  8. Belebele

    naoki Guest

    On Dec 11, 7:38 pm, Ondra Holub <> wrote:
    > On 11 Pro, 20:58, Belebele <> wrote:
    >
    >
    >
    > > > I am not sure if I understood exactly what you need. If you want to
    > > > store value of some templated type, you have to make the whole class
    > > > templated

    >
    > > That's not what I want. I want the Interface class to be a class, not
    > > a class template. That way, I could potentially assign to an object of
    > > the Interface class any object that implements the desired interface.
    > > That is:

    >
    > > class B1 {
    > > public:
    > > template <typename T>
    > > void foo(T );

    >
    > > };

    >
    > > class B2 {
    > > public:
    > > template <typename T>
    > > void foo(T );

    >
    > > };

    >
    > > B1 b1;
    > > Interface i(b1);
    > > i.foo(1);

    >
    > > B2 b2;
    > > i = b2;
    > > i.foo(1);

    >
    > > This is simple to implement if the interface does not contain method
    > > templates. I am lost when method templates are involved.

    >
    > I think it is not possible. You have to store the reference to other
    > class instance, so the referenced class would have to be derived from
    > some common class. It is hard to combine template polymorphism and
    > class polymorphism.


    Do this help you?

    #include <string>
    #include <iostream>

    struct Interface {
    template<typename T>
    void foo(T& t) {
    t.foo("foo()");
    }
    };

    class A {
    public:
    void foo(const std::string& parameter) {
    std::cout << "A::foo( " + parameter + " )" << std::endl;
    }
    };

    class B {
    public:
    void foo(const std::string& parameter) {
    std::cout << "B::foo( " + parameter + " )" << std::endl;
    }
    };

    int main() {
    Interface i;
    A a;
    B b;
    i.foo(a);
    i.foo(b);
    }

    But if you need to store the class reference passing it on Interface
    class constructor it is not possible unless you declare Interface as a
    class template.
     
    naoki, Dec 13, 2007
    #8
  9. Belebele

    naoki Guest

    On Dec 11, 5:58 pm, Belebele <> wrote:
    > > I am not sure if I understood exactly what you need. If you want to
    > > store value of some templated type, you have to make the whole class
    > > templated

    >
    > That's not what I want. I want the Interface class to be a class, not
    > a class template. That way, I could potentially assign to an object of
    > the Interface class any object that implements the desired interface.
    > That is:
    >
    > class B1 {
    > public:
    > template <typename T>
    > void foo(T );
    >
    > };
    >
    > class B2 {
    > public:
    > template <typename T>
    > void foo(T );
    >
    > };
    >
    > B1 b1;
    > Interface i(b1);
    > i.foo(1);
    >
    > B2 b2;
    > i = b2;
    > i.foo(1);
    >
    > This is simple to implement if the interface does not contain method
    > templates. I am lost when method templates are involved.


    Do this help you?

    #include <string>
    #include <iostream>

    struct Interface {
    template<typename T>
    void foo(T& t) {
    t.foo("foo()");
    }

    };

    class A {
    public:
    void foo(const std::string& parameter) {
    std::cout << "A::foo( " + parameter + " )" <<
    std::endl;
    }

    };

    class B {
    public:
    void foo(const std::string& parameter) {
    std::cout << "B::foo( " + parameter + " )" <<
    std::endl;
    }

    };

    int main() {
    Interface i;
    A a;
    B b;
    i.foo(a);
    i.foo(b);

    }

    But if you need to store the class reference passing it on Interface
    class constructor it is not possible unless you declare Interface as a
    class template.
     
    naoki, Dec 13, 2007
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. jpr
    Replies:
    2
    Views:
    351
    red floyd
    Mar 25, 2006
  2. John Goche
    Replies:
    10
    Views:
    797
    Marcus Kwok
    Dec 8, 2006
  3. Jonas Huckestein
    Replies:
    3
    Views:
    362
    Rolf Magnus
    Feb 12, 2007
  4. newbie
    Replies:
    6
    Views:
    419
  5. desktop
    Replies:
    7
    Views:
    332
    James Kanze
    May 11, 2007
Loading...

Share This Page