pl en

Include loops (C++)

Including header files is very often called by programmers one of the most important shortcoming of C++. Creators of modern languages, like C# or Java, try to eliminate it permanently.

But today C++ seems to be the best language to create efficient applications. Because of its versatile it has a lot of adherents (I'm one of them) and it is still the most popular programing language. So, we have no choice - we need to know how to use including effectually.

Poor / Nice designed header files structure

Before I will show you the substance of a case, let us answer the question: "What does it mean, header files in project are nice or poor projected?". The answer is quite easy. They are nice projected if they fulfill conditions:

  • if we will change the included files order, the program still compiles
  • if we will add any header file and program still compiles.

If classes in our project have tree like structure, it is very easy to fulfill these conditions. The problem appears if we have the loops.

What will we call "Loops problem"

It is easy to imagine a situation, when we have loops in references in our program. Let's consider an example when we have two-way tree. In this kind of tree "parent" contains pointers to all "childes" and every "child" contains a pointer to its "parent". More complicated loops are often met too (with wider loop-eyes, for example: class A needs to include definition of class B, class B needs to include definition of class C, class C needs to include definition of class A).

If project grows, the number of loops usually grows too. They start to overlap. Then it is impossible to add new class using existing ones, without solving problems with header files... At this point we usually start to think we need a global solution.

The global solution

First solution we can think about is easy: "Lets make one header file, including all components in right order. This way we will avoid horror". And Indeed, we will, but we have just made first step into another one: Every, even small change in any header file will force to compile whole sources. I think I don't need to describe you how low will be the productivity of developers.

Much better solution

Lets think a little and make some experiments: When do we really need to include header file with class definition:

Operation Do we need to include header file with class definition?
Inheritance yes
Containing yes
Containing pointer no
we need only add
class name;
Calling a method yes
Accessing member yes

Short look at the table and we have the following conclusions:

  • We need to include the definition of class A to class B header if:
    • B inherits from A
    • B contains A
  • Class A definition shouldn't be included to class B header:
    • Class B contains pointer to A - we need only add a line class A; into header of B (before definition of B)
  • In general we can't call any methods or access any members from other class in header. We can do it only if current class inherits from that class or object of that class is included into current class. Other calls or accesses should be moved to .cpp file, where we can include any header file without problems.

Using these rules we will create headers structure, which we will call "nice projected". We will have no problems with extending project and compilation time will not to long.

Example

----------- file a.h -----------

        
        class A
        {
        public:
                A();
                virtual ~A();
                
                int GetSomeValue();
        };
        
        

----------- file b.h -----------

        
        #include "a.h" // <- including because inheritance  
                
        class B :public A
        {
        public:
                B();
                virtual ~B();
        };
        
        

----------- file c.h -----------

        
        #include "d.h"
        
        class A;  // <- only pointer, we will include header in .cpp
        
        class C
        {
        protected:
                A * m_pA;
                D m_d;
        public:
                C(A *);
                ~C();
                
                A* GetA(){ return m_pA; }
                //inline int GetAValue(){ return m_pA->GetSomeValue(); } <- we can't do that!
                inline int GetDValue(){ return m_d.GetSomeValue(); }
        };
        
        

----------- file d.h -----------

        
        class C;
        
        class D
        {
        protected:
                C * m_pC; // <- classic loop, but no problems
        
        public:
                D();
                ~D();
                
                int GetSomeValue();
        };
        
        
Main page: akolacz.tarchomin.pl
css xhtml