header file include-loop and multiple definition

3.8k Views Asked by At

I have a util.h containing a function which will be used in a.h and 'b.h', and further more, a.h and b.h will include each other in order to access some classes defined in each other.

//util.h

#ifndef _UTIL_H_
#define _UTIL_H_

#include <iostream>

void foo()
{
    std::cout << "foo\n";
}

#endif

//a.h, it has a a.cpp
#ifndef _A_H_
#define _A_H_

#include "util.h"
#include "b.h"

//some classes' definition

#endif

//b.h, it has a b.cpp
#ifndef _B_H_
#define _B_H_

#include "util.h"
#include "a.h"

//some classes' definition

#endif

My problem is that, I got multiple definition error for foo. How?

I thought the problem might be that, a.h includes util.h and b.h, and b.h includes util.h once again, so I got multiple def error. But it can't seem to make sense, because in util.h I wrote #ifndef/#define guards.

Anyone can give me a help, thanks.

1

There are 1 best solutions below

2
On

Your problem is caused by defining rather than simply declaring foo inside utils.h

For this example, assume that we have:

a.cpp

#include "a.h"

b.cpp

#include "b.h"

main.cpp

#include "a.h"
#include "b.h"
#include "utils.h"


int main(){
    foo();
    return 0;
}

After preprocessing, but before compilation, your files now look like this (this is a simplification, but you get the idea):

a.cpp

void foo()
{
    std::cout << "foo\n";
}

b.cpp

void foo()
{
    std::cout << "foo\n";
}

main.cpp

void foo()
{
    std::cout << "foo\n";
}

int main(){
    foo();
    return 0;
}

Now when you compile, you have 3 definitions of foo (they're all identical, but this is irrelevant). After compilation, there is no way for the linker to know which definition to pick for any given call to foo and so it generates an error.

Instead of defining foo in the header, define it in utils.cpp and only put a declaration in utils.h, e.g.

utils.h

#ifndef _UTIL_H_
#define _UTIL_H_

void foo();

#endif

or, alternately, declare foo as static or inline:

utils.h

#ifndef _UTIL_H_
#define _UTIL_H_

static void foo()
{
    std::cout << "foo\n";
}

/* OR */

inline void foo()
{
    std::cout << "foo\n";
}


#endif

This is something you need to do only if you want to inline your function. In this case, the compiler needs a definition of the function in every translation unit where it is used, as it essentially becomes a compile-time macro.