Click here to Skip to main content
11,718,289 members (86,967 online)
Click here to Skip to main content

Simulation of Virtual Function with Template

, 2 Nov 2003 CPOL 64.9K 28
Rate this:
Please Sign up or sign in to vote.
Simulation of Virtual Function with Template

Introduction

Polymorphism can be achieved at run time using virtual function and at compile time using template [SUT01]. Both techniques have some pros and cons. The running time of virtual function is little bit slower than template. And implementation of virtual function takes some extra bytes too. On the other hand the code of template is little bit difficult to understand and takes longer time for compilation but this is faster than virtual function. And there is no overhead of extra bytes, in case of template, at run time. Polymorphism is not limited to inheritance and template. It can also be achieved by using overloading (function and operator overloading) and type conversion [COP98].

In case of virtual function, polymorphism is achieved by using inheritance and class hierarchies. Usually there is a common base class in the class hierarchies and all the classes are inheriting from it. But the problem with this approach is type, you have to downcast it. In fact you can achieve polymorphism in inheritance without using virtual function, but in that case you have to write some ugly code to retrieve the object [STR95].

So if you achieve polymorphism with the help of template then you can get two advantages, first there is no overhead of extra bytes and second there is no run time overhead, because in case of template everything has been resolved at compile time. And you can simulate some functionality of virtual function with the help of template. Before discussing how we can achieve this lets take a recap of virtual function first.

It is common misunderstanding in case of virtual function that you can get full power of it with the help of only reference and pointer. However you can do it without using reference or pointer. The best example of it is Template Design Pattern [GAM94]. The basic theme of virtual function is that, the function of that class is called whose object is created. Let's take a look at this example which is little bit similar to Template Design Pattern.

class B
{
public:
    void Fun() { vf(); }
    virtual void vf() { std::cout << "B::vf" << std::endl; }
};

class D : public B
{
public:
    void vf() { std::cout << "D::vf" << std::endl; }
}

Now create the object of Drive class and call the non virtual function Fun. It is not necessary to use base class reference or pointer; you can just create the object of drive class on stack and call the non virtual function.

D d;
d.Fun();

Drive class doesn't override the non virtual function so the base class function is going to be called. That non virtual function is going to call virtual function vf, but the question is which virtual function, base or drive? In this case drive class virtual function is going to call, because in case of virtual function, whose virtual function is called whose object we made. There is one more interesting point in this example; here with the help of virtual you can call the Drive class function from the base class.

Let's take a look at template version of this program, in which we are trying to do the same thing but without using any virtual function.

template <typename T>
class B
{
public:
    void Fun() 
    { 
        T* pT = static_cast<T*>(this);
        pT->vf();
    }
    void vf() { std::cout << "B::vf" << std::endl; }
};

class D : public B<D>
{
public:
    void vf() { std::cout << "D::vf" << std::endl; }
};

Calling of the function is similar to the previous program

D d;
d.Fun();

The result of this program is same as previous program. So here we simulate the behavior of virtual function without using the virtual keyword and do the polymorphism at compile time not at run time. And of course there is no overhead of extra byte and no indirection just like virtual function, so this program runs faster then the equivalent virtual function program.

If everything is better than virtual function then why shouldn't we use template in all the cases in which are used to use virtual function? It is clear after taking a closer look at the above approach that this technique is not exactly equivalent of virtual counterpart. The first notable difference is that you can call the drive class function whose return type is different (e.g. int in the above case) then the base class function which is not possible in case of virtual function. You can override function whose return type is exactly same or should be drive class if the base class function returns the class, just like in Factory and Abstract Factory design pattern [GAM94] for example.

class B
{
public:
    virtual B* CreateInstance();
};

class D : public B
{
public:
    D* CreateInstance();
};

But in case of template version you can call the drive class function whose return type is totally different or not drive class of the base class functions return class.

The other difference is, in case of virtual function, if you declare any function virtual then it will remain virtual no matter how deep you make the inheritance chain. But in template version you can achieve the polymorphic behavior to only the immediate drive class and not after that.

In case of virtual you can take the base class pointer or reference and store the address of drive class in it. Ok you can do the same thing with the help of template version and get the same result.

B<D>* pB = new D;
pB->Fun();

But in case of virtual function you can inherit more than one class from base and store the address of any of its drive class in base class pointer. You can make a function which accepts the function (or reference) of base class and pass any of its drive class in it. But in case of template version the base class is template and need one template parameter and what will be pass as a template parameter if there are more than one drive classes are mad by the base class. The solution of this problem is simple, just make that function template too and pass drive class as a template parameter.

template <typename T>
void fun(const B<T>& p)
{
    p.Fun();
}

Now suppose you inherit two classes from base class named D1 and D2, then calling the function is just like any other function.

D1 d1;
D2 d2;
fun(d1);
fun(d2);

Of course now the Fun member function should be constant, because we pass it as a constant reference of base class. On the other hand you have to remove the constant ness of this function by using const_cast.

We have solve the problem in case of passing parameter to function but what will be the template parameter if we try to make the array of pointers of base class and want to store the address of different drive classes in different index of array?

// what will be the template parameter?
B<?>* arrB[10];

There is no equivalent of this in template version. So template version simulate only limited functionality of virtual functionality not all of its functionality.

Reference

  1. [COP98] Multi Paradigm Design for C++. James O. Coplien
  2. [GAM94] Design Patterns Elements of Reusable Object Oriented Software. Erich Gamma et al.
  3. [STR95] The Design and Evolution of C++. Bjarne Stroustrup
  4. [SUT01] More Exceptional C++ 40 New Engineering puzzles, programming problems and solutions. Herb Sutter

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Zeeshan Amjad
Software Developer (Senior) Bloomberg LP
United States United States
Working as a Sr C++ Developer at Bloomberg LP

You may also be interested in...

Comments and Discussions

 
QuestionWhen to use Virtual functions against templates? Pin
Venkat Konuganti7-Aug-05 9:08
memberVenkat Konuganti7-Aug-05 9:08 
GeneralAnother way to simulate a similar thing: Mixin Pin
tpolzin14-Sep-04 4:14
membertpolzin14-Sep-04 4:14 
QuestionAre there any reasons why static_cast would give the wrong address? Pin
John M. Drescher3-May-04 5:26
memberJohn M. Drescher3-May-04 5:26 
GeneralThanks.. Pin
Bernhard3-Nov-03 20:51
memberBernhard3-Nov-03 20:51 
GeneralRe: Thanks.. Pin
Zeeshan Amjad15-Sep-04 3:34
memberZeeshan Amjad15-Sep-04 3:34 
GeneralATL does exactly this.. Pin
juggler3-Nov-03 3:21
memberjuggler3-Nov-03 3:21 
GeneralRe: ATL does exactly this.. Pin
Jörgen Sigvardsson4-Nov-03 13:18
memberJörgen Sigvardsson4-Nov-03 13:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150901.1 | Last Updated 3 Nov 2003
Article Copyright 2003 by Zeeshan Amjad
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid