Compile-time virtual function calls in C++

21 August, 2009 § 7 Comments

C++ templates provide some really fascinating abilities, one of which is compile-time virtual function calls. WTL, the Windows Template Library, uses compile-time virtual function calls when deriving types. In this post, I will cover what I mean when I say “compile-time virtual function calls”, and how they create faster code and smaller executables.

By far, below is the most common use of templates within C++ code:

namespace std {
   template <typename T>
   class vector {
      /* ... */
   }
}
std::vector<int> primeNumbers;

But what if we wanted to derive our own type, with a templated class being the base type? See this example:

template <typename T>
class WindowImpl {
   int id_of_windowImpl;
   static LPCTSTR GetWindowCaption() { return NULL; }
   void DrawWindow() {
      LPCTSTR windowTitle = T::GetWindowCaption();
      /* Draw window and place title at top of UI */
   }
} 

Did you notice that there was no mention of the keyword virtual? This is where our little trick comes in. Let’s say we wanted to make our own boring derivation of Window, one that has the title of “Basic Window”. We could simply do this:

class BasicWindowImpl : WindowImpl<BasicWindowImpl> {
   int id_of_basicWindowImpl;
   static LPCTSTR GetWindowCaption() {
      return _T("Basic Window");
   }
}

BasicWindowImpl<BasicWindowImpl> basicWindow;

When the code is compiled, the static method GetWindowCaption will be called on the derived type. If the method isn’t implemented in the derived type, then the C++ lookup rules state that it will look deeper in the class and find the base implementation that returns NULL.

Also, this whole practice is made possible since immediately following the colon, the type has been declared and the typename can be used as a template parameter.

What does this mean in terms of efficiency/footprint?

First a short high level overview on how virtual functions are implemented. When a method inside of a class is declared virtual, a special data type is added to the class. This data type stores function offsets from the base of the class. When a call is made using a base type, this virtual function table (vftbl or vtable for short) is referenced and the memory address of the function is retrieved and executed.

Each instance of a class will hold a pointer to this table (often called a vpointer). This pointer is usually initialized at the end of the constructor by some hidden code that your C++ compiler generates.

On a 32-bit machine with 32-bit ints and no virtual functions: basicWindow is 8 bytes (4 bytes for each int that it holds).

On a 32-bit machine with 32-bit ints and virtual functions: basicWindow is 12 bytes (the same 8 bytes plus 4 bytes for the vpointer). Also, there is another 4 bytes used for the vtable and it’s one function pointer that is stored and pointing to BasicWindowImpl::GetWindowCaption.

In summary, by using compile-time virtual function calls, the sample code cuts it’s memory use in half. The vtable pointer does not consume much memory, but if there were 1,024 BasicWindowImpl instances created, then an extra 4kb of data would be unnecessarily used. Also, there is no need to look up the function address in the table due to the static linking of the overriden function at compile-time.

This brings you a smaller and faster executable by making your compiler work just a little harder.

Tagged: , ,

§ 7 Responses to Compile-time virtual function calls in C++

  • A.J. says:

    Hey Jared,

    First of all; that is pretty cool! I tried it out a little bit; and had to see if this could work for non-static methods as well. The following was added into the WindowImpl class:
    typename T* m_pThis;
    WindowImpl()
    {
    m_pThis = (T*) this;
    }
    void DoSomething()
    {
    std::string s1 = m_pThis->GetFromNonStaticMethod();
    }

    So though that worked; and still doesn’t use the keyword virtual; it does add in a pointer whereas your static example didn’t need to add a pointer. There still might be a performance improvement though. I didn’t do any tests for performance.

    Also static_cast(this)->SomeNonStaticMethod(); also works; but because of the cast I think the performance improvement would suffer.

  • A.J. says:

    Whoops that’s static_cast(this)->SomeNonStaticMethod();🙂

  • msujaws says:

    I think that WordPress is getting rid of your typename due to the angled brackets. This is probably what you meant, static_cast<T*>( this )->SomeNonStaticMethod();

    Anyways, there shouldn’t be any performance hit for using a *static* cast, since it is done at compile time. Only dynamic_casts will introduce RTTI and a performance hit at runtime.

  • A.J. says:

    Oh you’re right Jared. I recalled earlier with #includes doing &_l_t_; and &_r_t_; without the _’s; but apparently forgot. Yeah you’re right static_casts shouldn’t cause a performance hit.

  • A.J. says:

    All was going well; and then I thought of a use case and the use case has interfaces.

    class MyInterface{ public: virtual void SomeMethod() = 0; };

    template<typename T>
    class A : public MyInterface//Now has a VTable
    {
    public:
    void SomeMethod(){}
    };

    And I ended up adding a vtable. Though it could be a shorter VTable since many methods are not virtual anymore.

  • Samsinite says:

    What about if we wanted to inherit from the concrete classes defined from an abstract class? Then wouldn’t we loose our ability to be able to create polymorphic calls on the new class that use the existing concrete classes? Or am I missing something. If I am correct, then this implementation wouldn’t be as useful in these cases. Or, what if we add a template T to each inherited class so the type can be passed down the line through the template parameter?
    Also, not sure if this has been noted, but this technique could allow for a bit of compiler optimization too.

  • Samsinite says:

    Nevermind about passing the type down the line through a template parameter, an “unspecialized class template can’t be used as a template argument for a template parameter”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

What’s this?

You are currently reading Compile-time virtual function calls in C++ at JAWS.

meta