How Can a C++ Header File Include Implementation

How can a C++ header file include implementation?

Ok, not a C/C++ expert by any means, but I thought the point of a header file was to declare the functions, then the C/CPP file was to define the implementation.

The true purpose of a header file is to share code amongst multiple source files. It is commonly used to separate declarations from implementations for better code management, but that is not a requirement. It is possible to write code that does not rely on header files, and it is possible to write code that is made up of just header files (the STL and Boost libraries are good examples of that). Remember, when the preprocessor encounters an #include statement, it replaces the statement with the contents of the file being referenced, then the compiler only sees the completed pre-processed code.

So, for example, if you have the following files:

Foo.h:

#ifndef FooH
#define FooH

class Foo
{
public:
UInt32 GetNumberChannels() const;

private:
UInt32 _numberChannels;
};

#endif

Foo.cpp:

#include "Foo.h"

UInt32 Foo::GetNumberChannels() const
{
return _numberChannels;
}

Bar.cpp:

#include "Foo.h"

Foo f;
UInt32 chans = f.GetNumberChannels();

The preprocessor parses Foo.cpp and Bar.cpp separately and produces the following code that the compiler then parses:

Foo.cpp:

class Foo
{
public:
UInt32 GetNumberChannels() const;

private:
UInt32 _numberChannels;
};

UInt32 Foo::GetNumberChannels() const
{
return _numberChannels;
}

Bar.cpp:

class Foo
{
public:
UInt32 GetNumberChannels() const;

private:
UInt32 _numberChannels;
};

Foo f;
UInt32 chans = f.GetNumberChannels();

Bar.cpp compiles into Bar.obj and contains a reference to call into Foo::GetNumberChannels(). Foo.cpp compiles into Foo.obj and contains the actual implementation of Foo::GetNumberChannels(). After compiling, the linker then matches up the .obj files and links them together to produce the final executable.

So why is there an implementation in a header?

By including the method implementation inside the method declaration, it is being implicitly declared as inlined (there is an actual inline keyword that can be explicitly used as well). Indicating that the compiler should inline a function is only a hint which does not guarantee that the function will actually get inlined. But if it does, then wherever the inlined function is called from, the contents of the function are copied directly into the call site, instead of generating a CALL statement to jump into the function and jump back to the caller upon exiting. The compiler can then take the surrounding code into account and optimize the copied code further, if possible. 

Does it have to do with the const keyword?

No. The const keyword merely indicates to the compiler that the method will not alter the state of the object it is being called on at runtime.

What exactly is the benefit/point of doing it this way vs. defining the implementation in the CPP file?

When used effectively, it allows the compiler to usually produce faster and better optimized machine code.

What's the benefit for a C source file include its own header file

The main benefit is having the compiler verify consistency of your header and its implementation. You do it because it is convenient, not because it is required. It may definitely be possible to get the project to compile and run correctly without such inclusion, but it complicates maintenance of your project in the long run.

If your file does not include its own header, you can accidentally get in a situation when forward declaration of a function does not match the definition of the function - perhaps because you added or removed a parameter, and forgot to update the header. When this happens, the code relying on the function with mismatch would still compile, but the call would result in undefined behavior. It is much better to have the compiler catch this error, which happens automatically when your source file includes its own header.

Different implementations of a C header file

This maybe jumping in a bit too much at the deep end, but:

You might be after a pointer to function plus several implementations of functions with different names that do the task.

MoveAgent.h

extern MoveDirection (*takeDirection)(GameState *gs);

MoveAgent.c

MoveDirection takeDirectionRandom(GameState *gs)
{
...
}

MoveDirection takeDirectionSpiral(GameState *gs)
{
...
}

Mover.c

#include "MoveAgent.h"

// Default move is random
MoveDirection (*takeDirection)(GameState *gs) = takeDirectionRandom;

void setRandomMover(void)
{
takeDirection = takeDirectionRandom;
}

void setSpiralMover(void)
{
takeDirection = takeDirectionSpiral;
}

void mover(GameState *gs)
{
...;
MoveDirection dir = takeDirection(gs);
...;
}

So, somewhere along the line, you call one of the setXxxxxMover() functions, and thereafter you move using the mechanism set by the last of the two functions called.

You can also invoke the function using the long-hand notation:

    MoveDirection dir = (*takeDirection)(gs);

Once upon a very long time ago (1980s and earlier), this notation was necessary. I still like it because it makes it clear (to me) that it is a pointer-to-function that is being used.

Do including header files make the program heavier in c

Including header files inserts all the content from them into the translation unit on pre-processing.

If the include has only declarations(which is usually the case) and the functions are implemented in library files, the code doesn't get heavier. If the header files include implementation, it will be compiled on compilation, thus making the file heavier.

You can read more about compilation steps here:
http://www.tenouk.com/ModuleW.html

Should a .c file include something that it's .h file already includes?

The second paragraph is talking about one special case: the .cc file that implements the functions declared in the corresponding .h file. Since the .cc and .h file are intended to be closely related and maintained in tandem (often by the same programmer), the .cc file can depend on what's in its related header file.

The first paragraph is talking about other files that include the header file.

So foo.cc can depend on the includes in foo.h, but bar.cc should include both foo.h and baz.h.



Related Topics



Leave a reply



Submit