Cross-casting between templates

Discussion in 'C++' started by Jon Øyvind Kjellman, Mar 3, 2009.

  1. Hi, suppose you have the following classes:

    #include <iostream>

    class Foo {
    public:
    virtual void foo() { std::cout << "Foo::foo()\n"; }
    virtual ~Foo() {}
    };

    class Bar {
    public:
    virtual void bar() { std::cout << "Bar::bar()\n"; }
    virtual ~Bar() {}
    };

    class FooBar : public Foo, public Bar {
    public:
    void foo() { std::cout << "FooBar::Foo()\n"; }
    void bar() { std::cout << "FooBar::Bar()\n"; }
    };

    template<typename T>
    class Wrapper {
    T obj;
    public:
    T& get_obj() { return obj; }
    Wrapper(T obj) : obj(obj) { }
    ~Wrapper() { }
    };


    Now suppose you would like to use a Wrapper<FooBar*> object, but for it to also be castable to both Wrapper<Foo*> and Wrapper<Bar*> so that you could do something along the lines of the following snippet.


    void call_wrapped_foo(Wrapper<Foo*>& wrapped_foo)
    {
    wrapped_foo.get_obj()->foo();
    }


    void call_wrapped_bar(Wrapper<Bar*>& wrapped_bar)
    {
    wrapped_bar.get_obj()->bar();
    }

    int main(int argc, char** argv)
    {
    FooBar foobar;
    Wrapper<FooBar*> wrapped_foobar(&foobar);

    // Illegal!!
    call_wrapped_foo(dynamic_cast<Wrapper<Foo*> >(wrapped_foobar));
    call_wrapped_bar(dynamic_cast<Wrapper<Bar*> >(wrapped_foobar));
    }


    As expected the two last lines will not compile. However, can anyone suggest a pattern of some sorts that will allow me to do something similar (not necessarily dynamic_cast) without changing Foo, Bar or FooBar. Wrapper does not necessarily need to be a template and other helper classes may be added. I have thought about different pattern's involving virtual inheritance, but couldn't find something that will work. Short and elegant earns bonus points :)

    Regards,
    Jon Øyvind Kjellman
     
    Jon Øyvind Kjellman, Mar 3, 2009
    #1
    1. Advertising

  2. Jon Øyvind Kjellman wrote:

    > #include <iostream>
    >
    > class Foo {
    > public:
    > virtual void foo() { std::cout << "Foo::foo()\n"; }
    > virtual ~Foo() {}
    > };
    >
    > class Bar {
    > public:
    > virtual void bar() { std::cout << "Bar::bar()\n"; }
    > virtual ~Bar() {}
    > };
    >
    > class FooBar : public Foo, public Bar {
    > public:
    > void foo() { std::cout << "FooBar::Foo()\n"; }
    > void bar() { std::cout << "FooBar::Bar()\n"; }
    > };
    >
    > template<typename T>
    > class Wrapper {
    > T obj;
    > public:
    > T& get_obj() { return obj; }
    > Wrapper(T obj) : obj(obj) { }
    > ~Wrapper() { }
    > };
    >
    >
    > Now suppose you would like to use a Wrapper<FooBar*> object, but for it
    > to also be castable to both Wrapper<Foo*> and Wrapper<Bar*> so that you
    > could do something along the lines of the following snippet.
    >
    >
    > void call_wrapped_foo(Wrapper<Foo*>& wrapped_foo)
    > {
    > wrapped_foo.get_obj()->foo();
    > }
    >
    >
    > void call_wrapped_bar(Wrapper<Bar*>& wrapped_bar)
    > {
    > wrapped_bar.get_obj()->bar();
    > }
    >
    > int main(int argc, char** argv)
    > {
    > FooBar foobar;
    > Wrapper<FooBar*> wrapped_foobar(&foobar);
    >
    > // Illegal!!
    > call_wrapped_foo(dynamic_cast<Wrapper<Foo*> >(wrapped_foobar));
    > call_wrapped_bar(dynamic_cast<Wrapper<Bar*> >(wrapped_foobar));
    > }
    >
    >
    > As expected the two last lines will not compile. However, can anyone
    > suggest a pattern of some sorts that will allow me to do something
    > similar (not necessarily dynamic_cast) without changing Foo, Bar or
    > FooBar. Wrapper does not necessarily need to be a template and other
    > helper classes may be added. I have thought about different pattern's
    > involving virtual inheritance, but couldn't find something that will
    > work. Short and elegant earns bonus points :)


    You can provide constructors of a Wrapper from another Wrapper:

    template<typename T>
    class Wrapper
    {
    //.. your code
    template<typename Y>
    Wrapper(const Wrapper<Y>& y):eek:bj(y.obj){}
    };

    In your case, with pointer, you will be able to write:
    Wrapper<FooBar*> wrapped_foobar(&foobar);
    Wrapper<Foo*> wrapped_foo(wrapped_foobar);
    Wrapper<Bar*> wrapped_bar(wrapped_foobar);

    And if you change the signature of call_wrap_*() to take a const object,
    and add const accessor to Wrapper

    template<typename T>
    class Wrapper
    {
    //.. your code
    const T& get_obj()const{return obj;}
    };

    void call_wrapped_foo(const Wrapper<Foo*>& wrapped_foo){...}
    void call_wrapped_bar(const Wrapper<Bar*>& wrapped_bar){...}


    the creation of a temporary object is automatique and you can write:
    call_wrapped_foo(wrapped_foobar);
    call_wrapped_bar(wrapped_foobar);

    --
    Michael
     
    Michael DOUBEZ, Mar 4, 2009
    #2
    1. Advertising

  3. > You can provide constructors of a Wrapper from another Wrapper:
    >
    > template<typename T>
    > class Wrapper
    > {
    > //.. your code
    > template<typename Y>
    > Wrapper(const Wrapper<Y>& y):eek:bj(y.obj){}
    > };
    >
    > In your case, with pointer, you will be able to write:
    > Wrapper<FooBar*> wrapped_foobar(&foobar);
    > Wrapper<Foo*> wrapped_foo(wrapped_foobar);
    > Wrapper<Bar*> wrapped_bar(wrapped_foobar);
    >
    > And if you change the signature of call_wrap_*() to take a const object,
    > and add const accessor to Wrapper
    >
    > template<typename T>
    > class Wrapper
    > {
    > //.. your code
    > const T& get_obj()const{return obj;}
    > };
    >
    > void call_wrapped_foo(const Wrapper<Foo*>& wrapped_foo){...}
    > void call_wrapped_bar(const Wrapper<Bar*>& wrapped_bar){...}
    >
    >
    > the creation of a temporary object is automatique and you can write:
    > call_wrapped_foo(wrapped_foobar);
    > call_wrapped_bar(wrapped_foobar);
    >


    Thank you, that worked. Although, for my problem I had to drop the const qualifiers and I had to outsource some state data to a parent class so that the copy constructor could access it without making the data public. I couldn't find any other way for Wrapper<Foo*> to befriend Wrapper<Bar*>.
     
    Jon Øyvind Kjellman, Mar 9, 2009
    #3
    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. kevin
    Replies:
    11
    Views:
    5,810
    Andrew McDonagh
    Jan 8, 2005
  2. JKop
    Replies:
    3
    Views:
    480
  3. recover
    Replies:
    2
    Views:
    814
    recover
    Jul 25, 2006
  4. Wally Barnes
    Replies:
    3
    Views:
    529
    Wally Barnes
    Nov 20, 2008
  5. Sosuke

    Up casting and down casting

    Sosuke, Dec 20, 2009, in forum: C++
    Replies:
    2
    Views:
    565
    James Kanze
    Dec 20, 2009
Loading...

Share This Page