Cross-casting between templates

  • Thread starter Jon Øyvind Kjellman
  • Start date
J

Jon Øyvind Kjellman

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
 
M

Michael DOUBEZ

Jon said:
#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);
 
J

Jon Øyvind Kjellman

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*>.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top