Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

multiple definition in header file

Given this code sample:

complex.h :

#ifndef COMPLEX_H #define COMPLEX_H  #include <iostream>  class Complex { public:    Complex(float Real, float Imaginary);     float real() const { return m_Real; };  private:    friend std::ostream& operator<<(std::ostream& o, const Complex& Cplx);     float m_Real;    float m_Imaginary; };  std::ostream& operator<<(std::ostream& o, const Complex& Cplx) {    return o << Cplx.m_Real << " i" << Cplx.m_Imaginary; } #endif // COMPLEX_H 

complex.cpp :

#include "complex.h"  Complex::Complex(float Real, float Imaginary) {    m_Real = Real;    m_Imaginary = Imaginary; } 

main.cpp :

#include "complex.h" #include <iostream>  int main() {    Complex Foo(3.4, 4.5);    std::cout << Foo << "\n";    return 0; } 

When compiling this code, I get the following error:

multiple definition of operator<<(std::ostream&, Complex const&) 

I've found that making this function inline solves the problem, but I don't understand why. Why does the compiler complain about multiple definition? My header file is guarded (with #define COMPLEX_H).

And, if complaining about the operator<< function, why not complain about the public real() function, which is defined in the header as well?

And is there another solution besides using the inline keyword?

like image 370
Jérôme Avatar asked Apr 28 '10 07:04

Jérôme


People also ask

Can you put definitions in header files?

Yes, that is correct. The function will be defined in every place where you include its header. The compiler will care about putting only one instance of it into the resulting program, by eliminating the others.

How do you avoid multiple definitions in C++?

extern int x[]; This makes x visible, so code in other source files can access x , but only defines it in one place, so you don't violate the one definition rule, causing the linker to complain about multiple definitions.

What is multiple inclusion of header files?

If a header file happens to be included twice, the compiler will process its contents twice. This is very likely to cause an error, e.g. when the compiler sees the same structure definition twice. Even if it does not, it will certainly waste time.

How do I put multiple headers in one file?

Typically this is done by having a . h or . cpp file with all your #include s in; you then #include this file first in each file (or use the idea of a 'forced include': /Fi in msvc, -include with gcc). Each file that uses a given pch has to have the same defines and compiler options.


2 Answers

The problem is that the following piece of code is a definition, not a declaration:

std::ostream& operator<<(std::ostream& o, const Complex& Cplx) {    return o << Cplx.m_Real << " i" << Cplx.m_Imaginary; } 

You can either mark the function above and make it "inline" so that multiple translation units may define it:

inline std::ostream& operator<<(std::ostream& o, const Complex& Cplx) {    return o << Cplx.m_Real << " i" << Cplx.m_Imaginary; } 

Or you can simply move the original definition of the function to the "complex.cpp" source file.

The compiler does not complain about "real()" because it is implicitly inlined (any member function whose body is given in the class declaration is interpreted as if it had been declared "inline"). The preprocessor guards prevent your header from being included more than once from a single translation unit ("*.cpp" source file"). However, both translation units see the same header file. Basically, the compiler compiles "main.cpp" to "main.o" (including any definitions given in the headers included by "main.cpp"), and the compiler separately compiles "complex.cpp" to "complex.o" (including any definitions given in the headers included by "complex.cpp"). Then the linker merges "main.o" and "complex.o" into a single binary file; it is at this point that the linker finds two definitions for a function of the same name. It is also at this point that the linker attempts to resolve external references (e.g. "main.o" refers to "Complex::Complex" but does not have a definition for that function... the linker locates the definition from "complex.o", and resolves that reference).

like image 192
Michael Aaron Safyan Avatar answered Sep 28 '22 16:09

Michael Aaron Safyan


Move implementation to complex.cpp

Right now after including this file implementation is being compiled to every file. Later during linking there's a obvious conflict because of duplicate implementations.

::real() is not reported because it's inline implicitly (implementation inside class definition)

like image 31
XAder Avatar answered Sep 28 '22 16:09

XAder