c++templatesderived-classnon-virtual-interface

Non-virtual derivation: what do I really get from the compiler?


I am wondering what is produced by the compiler when using non-virtual derivation:

template< unsigned int D >
class Point
{
     int[D];
    // No virtual function
    // ...
};
class Point2 : public Point<2> {};
class Point3 : public Point<3> {};

Does the derivation here only imply compile-time checks? Or is there some other overhead?

I noticed my compiler produces equally sized objects when using Point2 or directly Point<2>. I deduce the derivation did not incur a vtable, and, as a consequence, no virtual call will ever be made.

Am I missing something?


Context

I want to provide a couple of predefined specializations of a given class template. I started with typedefs:

template< unsigned int D >
class Point
{
     int[D];
};
typedef Point<2> Point2;
typedef Point<3> Point3;

Alas, this prevents clients to use "simple" forward declarations:

// No #include <Point.h>
class Point2;    // 'Point2': redefinition; different basic types
class Point3;    // 'Point3': redefinition; different basic types

It is then mandatory to write this rather unintuitive piece of code:

// No #include <Point.h>
template< unsigned int > class Point;
typedef Point<2> Point2;
typedef Point<3> Point3;

This is why I discarded typedefs and used non-virtual derivation. Still, I am wondering what are all the implications.

(Another strategy would be to write the forward declaration once in a dedicated header file, à la #include <iosfwd>.)


Solution

  • Ok, looks like no one have so far given you an actual answer to your question:

    No, there is no overhead to non-virtual derivation. The compiler doesn't have to create a vtable, there are no virtual function calls, and all is well. It is typically implemented simply by placing an instance of the base class at the beginning of the derived class, so that a pointer to the derived class can be treated as a pointer to the base class as well. And then everything just works.

    Of course, constructor calls have to be forwarded, but they will usually get inlined, eliminating that overhead as well.

    However, if you use multiple base classes, it may introduce a tiny bit of overhead (depending on how the compiler implements it). Probably not much (the this pointer has to be adjusted from time to time), but theoretically, it is there.