Polymorphism (without virtual functions) with a method template.

B

Belebele

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

Ondra Holub

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);
// --------------------------------------
 
B

Belebele

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

Ondra Holub

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

Jonathan Mcdougall

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

Belebele

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

Jonathan Mcdougall

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_;
};
 
N

naoki

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

naoki

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.
 

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,776
Messages
2,569,603
Members
45,188
Latest member
Crypto TaxSoftware

Latest Threads

Top