C++ Forward Declarations

I wrote in an earlier post about forward declarations. There I gave a real world example and argued that is a very good idea to forward declare everything and I said that usually the main argument for forward declaration (at least from my experience) is speed of compilation. After I thought a little more on this subject I’ve realized that this topic is not covered in detail in the literature. Sure you can find out how to forward declare “stuff” but to actually find something that resembles a best common practice guide is hard: it’s hard to find reasons to actually do this. So, in this post, I will try to give some real life examples and show the many forms of forward declaring as best as I can.

Let’s say you’re developing a 2D game engine. Your game engine will be a library that you and possibly other users will use. The engine provides many abstractions and one of them is loading and drawing an image on screen. Now your engine supports many image formats by using several libraries like libpng, libjpeg etc. To abstract the various image formats you have a class called Image with the interface declared in Image.h.

#include <png.h>
#include <jpeg.h>

class Image
{
...
}

Your API interface has a sprite class that you can use to draw images on the screen in Engine/Sprite.h that looks something like this.

#include <Image.h>

class Sprite
{
public:
    Sprite(std::string& filename);
    Render();
private:
    Image* img;
}

What is wrong with the code above? The Sprite class should abstract away all the details concerning third party image libraries. But because Image is included in the header and in Image.h I include png.h and jpeg.h, it’s probable that some structures or symbols will be included in my code. This means that the client of the API must have access to the include files of libpng nd/or libjpeg. This is useless because the user of the library should not be concerned with other dependencies, because that’s the purpose of the engine: to hide complexity and to provide a nice interface that does things in a friendlier way. Even if it is not a problem including some more include paths in the build, it’s still wrong because you actually signal to the client of your API that is ok to directly use libpng and libjpeg and this defeats the entire purpose of the API.

The solution to this problem is called forward declaration. :)

class Image;  // forward declaration

class Sprite
{
...
}

Now you’ll have to include the header file in the corresponding Sprite.cpp file but everything from Image.h will be included only in the engine and not in the clients code.

So what are good rules of thumb of forward declaration?

  1. You can’t forward declare the classes that you inherit from and if you think a little about this, it’ll make sense.
  2. Things that come from the standard library can be ignored. Don’t bother to forward declare those because they are already available to every unit that is compiled.
  3. You can forward declare everything except for things mentioned at 1 and 2 (optional): classes, structs, typedefs.

Number 3 can bring some problems especially if you use a C library. C libraries tend to have a lot of defined types. One such example is the FreeType library. FT_Face is a defined type. So if you declare one in your *.h file as a member, how can you forward declare this? You have to forward declare everything starting from the struct, and typedefs.

struct FT_FaceRec_;  // first forward declare the struct
typedef struct FT_FaceRec_*  FT_Face;  // then forward declare the typedef because the typedef depends on the struct

So in order to forward declare FT_Face you have to search for the definition of the type and then forward declare the initial type (struct FT_FaceRec_) and then the new type (FT_Face) because the typedef declaration depends on the declaration of the struct.

This pretty much covers everything one needs to forward declare efficiently and I hope that the reasons to do this are compelling enough and are actually more important than compilation speed. It’s still good when something is done for the wrong reasons but the bad thing is that is easy to be inconsistent if those reasons are not strong enough to go all the way.

Advertisement
  1. Good article, I agree that forward declarations should be used as much as possible.

    The point about linking is not quite true. Just because you include a header from a library shouldn’t force you to link against that library — if you don’t use any of the functions of that library directly you should be fine. It does however, as you suggest, force you to have the header files of that library available.

      • Cristi
      • December 21st, 2011

      Yeah you’re right! The point that I was trying to make is that you expose the library that you’re trying to abstrat to the client of the API but it came out wrong. :)

  1. No trackbacks yet.

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 )

Connecting to %s

Follow

Get every new post delivered to your Inbox.