Is it possible to mimic dynamic polimorphism by template?

something like
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class base
{
  public :
    virtual void draw() const = 0;
    virtual void area() const = 0;
};

class rectangle : public base
{
  public :
    virtual void draw() const {std::cout<<"rectangel\n";}
    virtual void area() const {std::cout<<"rect area\n";}
};

class triangle : public base
{
  public :
    void draw() const {std::cout<<"triangle\n";}
    virtual void area() const {std::cout<<"tri area\n";}
};

void drawShape(base const *basePtr)
{
  basePtr->draw();
  basePtr->area();
}

int main()
{  
  rectangle recta;
  triangle tri;

  base *basePtr[2] = {0};
  basePtr[0] = &recta;
  basePtr[1] = &tri;

  for(size_t i = 0; i != sizeof_array(basePtr); ++i) //the most important part
  drawShape(basePtr[i]);

  std::cout <<"system pause"<<std::endl;
  std::cin.get();
  return 0;
}


The most important part is I want to iterate different strategies of draw and
area by for loop one by one.Do I have any way to make template simulate the
behavior of line 37 and 38?

Thanks a lot


Last edited on
What's wrong with what you have?
1
2
3
4
base *a = new base ...,
	*b = new rectangle ...,
	*c = new triangle ...;
//should work fine 
What's wrong with what you have?

Nothing is wrong, I only want to try to mimic the behavior of the dynamic polymorphism by template
it's an interesting question, but unfortunately, it's a brain**** due to differing paradigms

usually, dynamic polymorphism is for sharing an interface with different implementations
from the caller's POV, you have the same base and function call, but lots of different behavior

whereas a template is for sharing same implementations to avoid copy-pasting code
from the caller's POV, you have a different type, but the same behavior/algorithm

so their uses tend to be orthogonal with each other

----------------------------------------

template typing is, in a sense, stricter than dynamic polymorphism so you will have problems implementing a heterogenous array like you have above in your example

one way around this is to use boost/bind and boost/function to abstract away this strictness using lambda calculus

warning: it ain't very pretty (looks like 1 part template 3 part boost):

output:
rectangle
rect area
triangle
tri area


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
#include <vector>
#include <algorithm>

#include <boost/bind.hpp>
#include <boost/function.hpp>

using namespace std;

template<typename T>
void DrawShape( const T& t )
{
  t.draw();
  t.area();
}

void DrawIt( boost::function<void()> fn )
{
  fn();
}

class rectangle
{
  public:
    void draw() const {std::cout<<"rectangle\n";}
    void area() const {std::cout<<"rect area\n";}
};

class triangle
{
  public:
    void draw() const {std::cout<<"triangle\n";}
    void area() const {std::cout<<"tri area\n";}
};

int main()
{  
  rectangle recta;
  triangle  tri;

  vector< boost::function<void()> > v;
  v.push_back( boost::bind( DrawShape<rectangle>, recta ));
  v.push_back( boost::bind( DrawShape<triangle>,  tri   ));

  for_each( v.begin(), v.end(), DrawIt );

  return 0;
}


edit: I realize now that this is almost faking it, because you can replace the code above with boost::bind and boost::function and not use any templates at all!

as I mentioned before, the headache with your example is a dissonance caused by template's strict typing requirements and your use of a heterogenous array

edit: I take that back - since boost::bind and boost::function are totally using templates anyways, you are, indeed, using templates underneath (sorry, brain turning mushy at 4AM)

but it holds true that I can remove templates from the example posted above and just use the templates inside boost's implementation
Last edited on
That means if I change the codes to
1
2
3
4
5
6
template<typename T>
void DrawShape( const T& t )
{
  t.draw();
  t.area(44, 55);
}

Even boost::bind and boost::function wouldn't work?
Thanks
no, that's not what I mean - in fact, I mean just the opposite

I am saying that it is boost::bind and boost::function that's doing all the work (in other words, you can even eliminate that little chunk of code and totally call just boost::bind and boost::function!)

if you take a step back, this actually makes perfect sense

think about how dynamic polymorphism works - the compiler sets up a virtual table which contains function pointers to the proper methods depending on your base/child hierarchy

what are we doing with boost::bind and boost::function?

we are doing the binding ourselves at compile time by specifying which methods are bound to which objects!

even better - remember how I mentioned the problem with templates requiring strict types and function signatures? well, by using boost::bind and boost::function, we are transforming different function calls with different signatures into generic void (*fptr)() - by using this new standard signature, noted as boost::function<void()> in the code, we are able to transform a heterogenous array into a homogenous array (content all of the same type)!

the drawback with this methodology is, you lose some type-checking due to boost::function - at the time that you bind(); in other words, Lines 42-43 must be done correct or you will get the wrong result

it was an interesting exercise, but I wouldn't actually do this in production code, unless there is a very good reason to do so - since we are going through a function pointer anyways, I don't see much advantage doing it this way rather than using dynamic polymorphism

well, there is a small advantage - you can virtually stuff any functions you want into this array, and it will work - the method names don't even have to be the same - this kind of flexibility is useful if you are say, building your own compiler or interpreter, for instance

if you are thinking along the lines of lambda functions or functional programming, then this approach would make more sense
btw, if you do change that block of code, hard-coding as you mentioned, and you change the interfaces on Lines 26, 33, the code would work, as-is, because your change is hidden behind the binding

on Lines 42 and 43, you are just binding to DrawShape<>() so the boost mechanisms wouldn't even see your changes - they would just work
Thanks a lot, I think I would just use dynamic polymorphism rather than static polymorphism for now
Topic archived. No new replies allowed.