C++ templates and polymorphism?

Started by
9 comments, last by Zahlman 16 years, 2 months ago
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.
Advertisement
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.
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?
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-
Professional C++ and .NET developer trying to break into indie game development.
Follow my progress: http://blog.nuclex-games.com/ or Twitter - Topics: Ogre3D, Blender, game architecture tips & code snippets.
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
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.
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.
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.
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...
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.

This topic is closed to new replies.

Advertisement