If you search the web for examples of the best C++ source code, the Doom3 source code is mentioned frequently, with testimonials like this one.
I spent a bit of time going through the Doom3 source code. It's probably the cleanest and nicest-looking code I've ever seen.
Doom 3 is a video game developed by id Software and published by Activision. The game was a commercial success for id Software, with more than 3.5 million copies sold.
On November 23, 2011, id Software maintained the tradition and released the source code of its previous engine. This source code was reviewed by many developers. Here, for example, is feedback from Fabien (original source):
Doom 3 BFG is written in C++, a language so vast that it can be used to generate great code but also abominations that will make your eyes bleed. Fortunately id Software settled for a C++ subset close to “C with Classes” which flows down the brain with little resistance:
- No exceptions.
- No References (use pointers).
- Minimal usage of templates.
- Const everywhere.
- Classes.
- Polymorphism.
- Inheritance.
Many C++ experts no longer recommend the "C with classes" approach. However, Doom3 was developed between 2000 and 2004, which could explain the lack of modern C++ mechanisms.
Let’s explore its source code using CppDepend and discover what makes it so special.
Doom3 is organized into several projects. Here’s a list of them, along with some statistics about their types:

And here’s the dependency graph showing the relationships between them:

Doom3 defines many global functions. However, most of the processing is implemented in classes.
The data model is defined using structs. To get a concrete idea of how structs are used in the source code, the metric view above shows them as blue rectangles.
In the Metric View, the codebase is represented using a Treemap. Treemapping is a method for displaying tree-structured data by using nested rectangles. The tree structure follows the usual code hierarchy:
- Project contains namespaces.
- Namespace contains types.
- Type contains methods and fields.

As we can observe, many structs are defined — for example, more than 40% of DoomDLL types are structs. They are systematically used to define the data model. This practice is adopted by many projects, but this approach has a big drawback in the case of multithreaded applications: structs with public fields are not immutable.
There is one important argument in favor of using immutable objects: it dramatically simplifies concurrent programming. Think about it — why is writing proper multithreaded code such a hard task? Because it is hard to synchronize threads' access to resources (objects or other OS resources). Why is it hard to synchronize these accesses? Because it is hard to guarantee that there won't be race conditions between the multiple write and read accesses performed by multiple threads on multiple objects. What if there are no more write accesses? In other words, what if the state of the objects accessed by threads doesn't change? Then there is no more need for synchronization!
Let’s search for classes having at least one base class:

Almost 40% of structs and classes have a base class. In OOP, one of the main benefits of inheritance is polymorphism. Here are in blue the virtual methods defined in the source code:

More than 30% of methods are virtual. Few of them are pure virtual, and here’s the list of all the abstract classes defined:

Only 52 abstract classes are defined, 35 of which are pure interfaces, i.e., all their virtual methods are pure.

Let's search for methods using RTTI.

Very few methods use RTTI.
To summarize: only basic OOP concepts are used — no advanced design patterns, no overuse of interfaces and abstract classes, limited use of RTTI, and data is defined as structs.
Until now, nothing special differentiates this code from many others using "C with Classes" that are criticized by many C++ developers.
Here are some interesting choices made by its developers that help explain what makes the code special:
1. Provide a common base class with useful services.
Many classes inherit from idClass:

idClass provides the following services:
- Instance creation.
- Type info management.
- Event management.

2. Make string manipulation easy
Generally, strings are among the most commonly used types in a project. Many operations are performed on strings, so we need functions to manipulate them.
Doom3 defines the idStr class, which contains almost all the useful methods needed to manipulate strings—there’s no need to define your own methods, as is often the case with string classes provided by other frameworks.
3. The source code is highly decoupled from the GUI framework (MFC)
In many projects using MFC, the code is highly coupled with its types, and you can find MFC types everywhere in the code.
In Doom3, the code is highly decoupled from MFC; only GUI classes have a direct dependency on it, as shown by this CQLinq query:

This choice has a big impact on productivity. Only the GUI developers need to worry about the MFC framework; the other developers don’t have to spend time dealing with MFC.
4. It provides a very good utility library (idlib)
In almost all projects, the most used types are utility classes, as shown by the result of this query:

As we can observe, the most used ones are utilities. If C++ developers don’t use a good utility framework, they can spend much of their development time dealing with the technical layer.
idlib provides useful classes with all the methods needed to handle strings, containers, and memory, making developers’ work easier and allowing them to focus more on the game logic.
5. The implementation is very easy to understand
Doom3 implements a hard-coded compiler, and as C++ developers know, developing parsers and compilers is no easy task. However, the Doom3 implementation is very easy to understand, and its code is very clean.
Here’s the dependency graph of the classes used by the compiler:

And here’s a code snippet from the compiler source code:

We have already studied the source code of many parsers and compilers. But this is the first time we’ve come across a compiler whose source code is so easy to understand—and the same is true of the entire Doom3 codebase. It's magic. When we explore the Doom3 source code, we can't help but say: WOW, it's beautiful!
Summary
Even though Doom3’s design choices are fairly basic, its designers made many decisions that allow developers to focus more on the game logic and simplify the technical layer, significantly increasing productivity.
However, when using “C with Classes”, you have to know exactly what you are doing. You have to be an expert like the Doom3 developers. Beginners should not take the risk of ignoring modern C++ recommendations.
