Sign in to follow this  

C++ templates and polymorphism?

This topic is 3598 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Greetings, My question is whether or not it is possible to use templates along with polymorphism. My attempts so far have been unsuccessful and I'm thinking that it's not possible. So, are there any tricks or alternatives that can be used? For example, I believe it is impossible to make a template function virtual (all attempts have lead to compiler errors). So, I make as many BaseClass::Function(<type> value) as I could think of for each <type>, and then tried to make template <typename T> DerivedClass::Function(T value). This compiles and appears to work at first, but calling Function() on a BaseClass pointer pointing to a DerivedClass object invokes the BaseClass::Function() method and not the DerivedClass::Function(). Calling Function() on a DerivedClass pointer works as expected, though, so it seem as if the virtual portion of the BaseClass::Function declaration is being ignored. Any suggestions? Thanks.

Share this post


Link to post
Share on other sites
Because templates are compile-time polymorphism, and as such, have no need for virtual.


template < class T >
struct basic_something {
virtual foo( T value );
};

template < class T >
struct derived : public basic_something<T>
{
foo( T value ) {} // overriden
};

template < class T >
void bar( basic_something<T> * b, T value ) { // acts as virtual
b.foo( value );
};

basic_something<int> b1;
basic_something<float> b2;
basic_something<const std::string> * b3 = new basic_something<const std::string>();

bar( &b1, 10 );
bar( &b2, 10 );
bar( b3, "Hello World");



basic_something here is "polymorphic" class. No virtuals, bar acts as polymorphic function, but it's resolved at compile-time. With templates, everything needs to be resolved at compile-time.

The template needs to be fully specialized by the time you use it.

Share this post


Link to post
Share on other sites
Antheus,

I couldn't completely follow what you were talking about, so I created a test project and came up with this example.
struct base
{
template <class T>
void foo(T value)
{ // Do something.
value = value;
}
};

struct derived : public base
{
template <class T>
void foo(T value)
{ // Do something.
value = value;
}
};

base b;
derived d;
base* pb = &d;

b.foo(10.0);
d.foo(10.0);
pb->foo(10.0);
This is the example I had in mind. The problem with this is that 'pb->foo(10.0)' calls the base::foo() and not derived::foo(), even though 'pb' actually points to a derived class.

Is there a way to call 'pb->foo()' that will call derived::foo() when 'pb' points to a derived object? If not, what would be the next best method?

My ultimate goal relates to a GUI system. I want my BaseWidget class to have Set and Get methods for the value stored in the widget. I also want the Set and Get methods to be very flexible. For example, if I have a CheckBox class derived from BaseWidget, I want the calls Set(1), Set(true), and Set("true") all to set the CheckBox widget value to true/checked. That's easy enough to do (using a std::stringstream as my formatter) if I have a CheckBox handle. However, what if I only have a BaseWidget pointer that points to the CheckBox? How would it be possible for me to call any of the Set()'s on the BaseWidget pointer and still be able to execute the code required in order to properly parse the given value?

Share this post


Link to post
Share on other sites
Imagine templates as an automatic search-and-replace filter (ok, that's oversimplified ;)) that the compiler won't see anything of. An actual class only comes to life when to instantiate a template.

You can derive instantiated template classes from other instantiated template classes, eg.


template <typename T>
struct base
{
virtual void foo(T value)
{ // Do something.
value = value;
}
};

template <typename T>
struct derived : public base<T>
{
void foo(T value)
{ // Do something.
value = value;
}
};



But you cannot make a templated virtual method.
What would the compiler be supposed to do?
Create one virtual method in the vtable for each data type it knows of?

-Markus-

Share this post


Link to post
Share on other sites
I don't think I can make the entire class templated. If I do that, how would I ever make a 'std::list<BaseWidget*> ChildWidgets' for widget class that have children? I would have to make a list of BaseWidget pointers of a specific type, which is far too limiting.

Edit: Typo

Share this post


Link to post
Share on other sites
Quote:
Original post by Mantear
I don't think I can make the entire class templated. If I do that, how would I ever make a 'std::list<BaseWidget*> ChildWidgets' for widget class that have children? I would have to make a list of BaseWidget pointers of a specific type, which is far too limiting.



This is what templates *are not* for.

Use run-time polymorphism. Templates are compile-time polymorphism, and as such, you can't use containers for them. Template instances are concrete types.

With templates, you know at compile time, what concrete type something is. Typelists or boost::fusion allow you to define a list-like object that allows you to store arbitrary objects into same container. But those lists are modified entirely by compiler, and cannot be changed during run-time.

Use the right tool for the job. Templates can achieve what you want, and the knowledge you give the compiler allows it to make some pretty drastic optimizations - but it's not trivial.

Template meta-programming is incredibly powerful, but comes at expense of code simplicity.

Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus
Use run-time polymorphism.

This is what I'm trying to do. I am using polymorphism with pretty good success thus far (simple, clean, flexible code). The problem is, without using templates or some other method, I don't know how to keep my Set/Get methods flexible without adding a bunch of hand-written code for each and every widget.

My question still comes down to how should I go about creating flexible Set/Get methods for the widget classes while maintaining polymorphism? It sounds like templates are out. I don't know of any other way other than hand-writting every forseeable version that I might need.

Share this post


Link to post
Share on other sites
Quote:
Original post by Mantear

This is what I'm trying to do. I am using polymorphism with pretty good success thus far (simple, clean, flexible code). The problem is, without using templates or some other method, I don't know how to keep my Set/Get methods flexible without adding a bunch of hand-written code for each and every widget.


Yes, that's what you need to do.

C++ doesn't support properties. The usualy way this is solved is something like this:

template < class T >
class Property {
public:
void set(T value);
T get();
private:
T x;
};

class CheckBox : public Widget {
public:
Property<bool> checked;
Property<int> width;
Property<int> height;
};


But that doesn't really do much by itself.

Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus
Yes, that's what you need to do.


So something like this?
class BaseWidget
{
public:
virtual void Set(bool value) { /*some default behavior*/ }
virtual void Set(int value) { /*some default behavior*/ }
virtual void Set(const std::string& value) { /*some default behavior*/ }
};

class CheckBox : public BaseWidget
{
public:
void Set(bool value) { m_Value = value; }
void Set(int value) { Set(static_cast<bool>(value)); }
void Set(const std::string& value) { (value == "1" || value == "true") ? Set(true) : Set(false); }

private:
bool m_Value;
};

Just seems like there should be a better way. Maybe a better way means a better language...

Share this post


Link to post
Share on other sites
Quote:
Original post by Mantear
Quote:
Original post by Antheus
Yes, that's what you need to do.


So something like this?


No. None of this functionality belongs into widget or checkbox. It's completely unrelated.

Why is checkbox so concerned with storing a single boolean value? You'll have dozens of properties. IsChecked, Left, Right, Top, Bottom, Enabled, ReadOnly, Name, Label, Icon, Parent, events, .....

Look into boost::any, that's the closest you can get.

Quote:
Just seems like there should be a better way. Maybe a better way means a better language...


Likely. Python, PHP, Lua, something that is more dynamically typed.

The virtuals in the way you're using them not don't make any sense whatsoever. Checkbox is a widget, not a boolean value. Your widgets are composites of properties, not a single value.

Share this post


Link to post
Share on other sites
Quote:
Original post by Mantear
This is what I'm trying to do. I am using polymorphism with pretty good success thus far (simple, clean, flexible code). The problem is, without using templates or some other method, I don't know how to keep my Set/Get methods flexible without adding a bunch of hand-written code for each and every widget.

My question still comes down to how should I go about creating flexible Set/Get methods for the widget classes while maintaining polymorphism? It sounds like templates are out. I don't know of any other way other than hand-writting every forseeable version that I might need.


Consider trying to design an interface that doesn't revolve around getting and setting each piece of data. Try to imagine using the widget in a way that doesn't actually assume anything about the data in the implementation class. For GUI work, this tends to be somewhat more difficult, admittedly. What kinds of things were you planning to get/set?

Share this post


Link to post
Share on other sites

This topic is 3598 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this