Pergunta

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>.)

Foi útil?

Solução

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.

Outras dicas

I don't really see what the problem is with using typedefs here. This is the sort of thing that typedef was intended for. I believe that there are a few restrictions when working in namespaces, but it doesn't look like you're doing that here. It's quite common to see something like this:

General.h

#include <map>
#include <string>

class MyObj1;
class MyObj2;

typedef map< string, MyObj1 > MyObj1Map;
typedef map< string, MyObj2 > MyObj2Map;

You can then include that in your source code, though you'll have to remember to include the definition of MyObj1 and MyObj2 where the compiler will need to know the size (i.e other than references and pointers in declarations.)

I always go with the forward declaration (the typedef one), because of the following reasons;

  1. Inheritance is an alternative to generics.

The problem with inheritance is that you have to redefine the constructors.

The standard solution (I don't see why you don't want it) is a dedicated header:

// File PointFwd.h
#ifndef POINT_FWD_H
#define POINT_FWD_H 1

template <unsigned> class Point;

typedef Point<2> Point2;
typedef Point<3> Point3;

#endif

Your clients only have to include "PointFwd.h" to forward declare what they want.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top