3

I realize that there are a lot of "multiple definition" questions out here already, but I've spent the past 2 hours looking for an explanation and haven't found one. So sorry if this is a duplicate.

Right now I have 2 classes: Array.h and Vector.h. Neither has any global variables, and neither is dependent on the other (i.e. Array doesn't use Vector and Vector doesn't use Array). The implementations are in the .h files.

Here's my Main.cpp:

#include <iostream>
#include "Array.h"
#include "Vector.h"
using namespace std;

int main() {
    cout << "Done" << endl;

    return 0;
}

...and everything runs fine. However, when I create another .cpp file with only #include statements...

DataReader.cpp

#include "Array.h"
#include "Vector.h"

...then everything blows up and I get a whole slew of errors for every method, constructor, and operator overload in Vector:

DataReader.o: In function `Vector':
C:\C++\Eclipse CDT\workspace\3D_Adaptive_FEM\Debug/..//Vector.h:49: multiple definition of `Vector::Vector()'
TestMain.o:C:\C++\Eclipse CDT\workspace\3D_Adaptive_FEM\Debug/..//Vector.h:49: first defined here
DataReader.o: In function `Vector':
C:\C++\Eclipse CDT\workspace\3D_Adaptive_FEM\Debug/..//Vector.h:53: multiple definition of `Vector::Vector(int const&, int const&, int const&)'
TestMain.o:C:\C++\Eclipse CDT\workspace\3D_Adaptive_FEM\Debug/..//Vector.h:53: first defined here
DataReader.o: In function `Vector':
C:\C++\Eclipse CDT\workspace\3D_Adaptive_FEM\Debug/..//Vector.h:56: multiple definition of `Vector::Vector(double const&, double const&, double const&)'
TestMain.o:C:\C++\Eclipse CDT\workspace\3D_Adaptive_FEM\Debug/..//Vector.h:56: first defined here
DataReader.o: In function `ZNK6Vector1xEv':
C:\C++\Eclipse CDT\workspace\3D_Adaptive_FEM\Debug/..//Vector.h:59: multiple definition of `Vector::x() const'
TestMain.o:C:\C++\Eclipse CDT\workspace\3D_Adaptive_FEM\Debug/..//Vector.h:59: first defined here

etc...

But if I just have #include "Array.h" in DataReader.cpp, then everything runs fine!

What can possibly be wrong with #include "Vector.h" that doesn't apply to #include "Array.h"?

Edit: Separating the implementations into .cpp files fixes the errors, but that doesn't explain why I have to do it for Vector and not Array.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
nebulabrot
  • 465
  • 1
  • 6
  • 13

1 Answers1

10

I suspect you have out-of-line definitions of these functions in you header. E.g.

#ifndef VECTOR_H
#define VECTOR_H

class Vector
{
public:
    Vector(int x, int y, int z);
private:
    int m_x, m_y, m_z;
};

Vector::Vector(int x, int y, int z)
    : m_x(x), m_y(y), m_z(z)
{}

#endif

Since the definition of the constructor is not inline in the class definition, the compiler does not make it implicitly inline. Now, if you include the same file in multiple translation units (i.e. *.cpp files), the linker will produce exactly the error you see, because each of the *.cpp files will contain its own definition of the constructor without them being marked as inline functions.

The solution is easy, just put a inline in front of the constructor declaration:

class Vector
{
public:
    inline Vector(int x, int y, int z);
    // ...
};

// ...

Alternatively, if the function body is short, as is the case with the constructor shown above, directly inline the function definition into the class definition, as

class Vector
{
public:
    Vector(int x, int y, int z)
        : m_x(x), m_y(y), m_z(z)
    {}
    // ...
};

// ...
Michael Wild
  • 24,977
  • 3
  • 43
  • 43
  • 1
    One more reason to separate interface from implementation. In subtle cases like initializing the members inlining might be ok, but in anything more complex the correct way would be to move the implementation to a dedicated `.cpp` source file – SomeWittyUsername Feb 19 '13 at 09:10
  • 2
    @icepack Apparently you have never programmed with templates... With the Intel compiler being the only exception I'm aware of, no current compiler allows you to separate interface from implementation of templates the way they do for non-templated code. – Michael Wild Feb 19 '13 at 09:23
  • There is a holywar regarding the correctness of inline/outline template definition, but that's another topic. Template isn't an interface. – SomeWittyUsername Feb 19 '13 at 09:41
  • Hu? Why are *templates no interface*? There's no problem with just declaring a template class or a template function provided you deliver the implementation later on or declare an explicit instantiation/specialisation for which you provide the implementation in a separate translation unit. – Michael Wild Feb 19 '13 at 09:49
  • Exactly. It can become real entity (e.g. interface) once you instantiate it. Before that it's just a bunch of meta-code. – SomeWittyUsername Feb 19 '13 at 11:41
  • @icepack I think you are missing the point - you can't separate interface from implementation with templates _as easily_ as you can with non-template code. – moodboom Feb 21 '15 at 02:11
  • 1
    @moodboom Not easily and not possible are two different things. – SomeWittyUsername Feb 21 '15 at 08:31
  • Yup :-) What's your preferred way? I'm considering if it's worth it to move implementation to a different .inl file or something. But it may be a sign of a problem, as the template code should be tight and only involve what actually needs templating, it seems to me. – moodboom Feb 21 '15 at 14:04
  • Strangely enough, this seems to only be a problem for me with templated function definitions which have specializations. I don't understand why gcc would be fine with the ones without specialization. – Gauthier Dec 25 '16 at 20:27