Home > Software engineering >  Declaring an object in a header when its definition is in a different header
Declaring an object in a header when its definition is in a different header

Time:10-15

I am new to cpp, looking at an existing project.

There are several places in the project where an object is defined in a namespace in some header file and then declared in the same namespace and used in other declarations in some other header file. Example:

MyStruct.hpp:

namespace A { struct MyStruct { int i; }; }

MyClass.hpp:

namespace A { struct MyStruct; }

namespace B {
  class MyClass {
  private:
    void foo(A::MyStruct& s);
  };
}

MyClass.cpp:

#include "MyClass.hpp"
#include "MyStruct.hpp"

namespace B {
  class MyClass {
    void foo(A::MyStruct& s) { /* ... */ }
  };
}

I might have expected there to be an #include "MyStruct.hpp" in MyClass.hpp, but that is not the case. I guess when the two header files are isolated there is not yet any relationship between the MyStruct objects in that case. Why does this not create some conflict though when the two headers are loaded together in the implementation file? I cannot, for instance, write int j; int j = 0;. Does the order of the #includes matter? And what might be the motivation for doing this?

CodePudding user response:

What you are seeing is a forward declaration being used.

Since foo() takes a MyStruct by reference, MyClass.hpp doesn't need to know the full declaration of MyStruct in order to declare foo(), it only needs to know that MyStruct exists somewhere. The linker will match them up later.

MyClass.cpp, on the other hand, needs to know the full declaration of MyStruct in order for foo()'s implementation to access the contents of its s parameter. So MyStruct.hpp is used there instead.

This also means that if the contents of MyStruct.hpp are ever modified, any source files using MyClass.hpp don't have to be recompiled since the forward declaration of MyStruct won't change (unless the namespace is changed, that is). Only files that are using MyStruct.hpp will need recompiling, like MyClass.cpp.

CodePudding user response:

MyClass.hpp contains a forward declaration of MyStruct; it’s just telling the compiler that a type named struct MyStruct exists, but not providing any details about what’s in the struct. That’s enough for things like const MyStruct & to compile without syntax errors, but not enough to actually do anything with the struct (since its size and contents are still unknown to the compiler)

As for why someone would do that instead of putting in an #include; it’s a little bit faster to compile, but the main reason would be to avoid cyclic dependencies (eg if MyStruct.h needs to reference MyClass but MyClass.h also needs to reference MyStruct, that would be difficult to achieve using only #include directives)

  •  Tags:  
  • c
  • Related