1

The following code generates errors LNK2005 & LNK1169 on Visual Studio 2019.

LNK2005: "void__cdecl OverloadingPlus(void)" (?OverloadingPlus@@YAXXZ) already defined in main.obj
LNK1169: one or more multiply defined symbols found

I reached this point by following a course on Udemy, where the instructor seems to have no problems with it.

Similar questions seem to be related to using global variables, defining functions in the header file, not using #ifndef guards... but as far as I can tell, that doesn't seem to be the case.

This problem started appearing only after the operator+ overload was included, but the operator<< doesn't trigger any errors, even though they have been declared and defined in the same manner.
Interestingly enough, if I remove any reference to OverloadingPlus.h file, and add #include Complex.h to main.cpp, the problem goes away.
I fail to see how including Complex.h in OverloadingPlus.h is contributing to a multiple definition of the operator+ exclusively, even though it is only included once in the entire project and the definitions are implemented in Complex.cpp and not in the header file, as pointed out in answers to similar problems.
Also tried surrounding the content of OverloadingPlus.h with an #ifndef statement just to make sure it is only used once which did not change a thing.
I attempted to declare a diferent operator+ overload inside the class (you can see it commented out), but it produces the same errors.
Commented all references to any other files trying to make sure Complex definitions are only included once. Didn't help either.

The code is the following:
main.cpp

//#include "OverloadingAssignmentOperator.h"
//#include "OverloadingLeftBitShiftOperator.h"
//#include "ComplexNumberClass.h"
#include "OverloadingPlus.h"

int main() {
    //OverloadingAssignmentOperator();
    //OverloadingLeftBitShiftOperator();
    //ComplexNumberClass();
    OverloadingPlus();

    return 0;
}

OverloadingPlus.h

#ifndef OVERLOADING_PLUS_H
#define OVERLOADING_PLUS_H

#include "Complex.hpp"

using namespace complex;

void OverloadingPlus() {
    Complex c1(1, 4);
    Complex c2(3, 2);

    std::cout << c1 + c2 << std::endl;
}
#endif 

Complex.hpp

#ifndef COMPLEX_HPP
#define COMPLEX_HPP

#include <iostream>

namespace complex {

    class Complex {
    private:
        double real;
        double imaginary;

    public:
        Complex();
        Complex(double, double);
        Complex(const Complex&);

        const Complex& operator=(const Complex& other);
        //const Complex operator+(const Complex& r);

        double getReal() const { return real; }
        double getImaginary() const { return imaginary; }
    };

    Complex operator+(const Complex& l, const Complex& r);
    std::ostream& operator<<(std::ostream& out, const Complex& c);
}

#endif // !__COMPLEX_HPP__

Complex.cpp

#include "Complex.hpp"

namespace complex {
    Complex::Complex() : real(0), imaginary(0) {}
    Complex::Complex(double r, double i) : real(r), imaginary(i) {}
    Complex::Complex(const Complex& other) {

        std::cout << "Copy constructor..." << std::endl;

        real = other.real;
        imaginary = other.imaginary;
    }

    const Complex& Complex::operator=(const Complex& other) {
        real = other.real;
        imaginary = other.imaginary;

        return *this;
    }

    //const Complex Complex::operator+(const Complex& r) {
    //  return Complex(real + r.getReal(), imaginary + r.getImaginary());
    //}

    // 

    Complex operator+(const Complex& l, const Complex& r) {
        return Complex(l.getReal()+r.getReal(), l.getImaginary()+r.getImaginary());
    }

    std::ostream& operator<<(std::ostream& out, const Complex& c) {
        out << "(" << c.getReal() << "," << c.getImaginary() << ")";
        return out;
    }
}
Lera
  • 33
  • 1
  • 7
  • What are the complete errors you're receiving? Copy/Paste them into the question. – Retired Ninja Jun 02 '21 at 12:09
  • @jabaa Tried it but it did not solve the issue – Lera Jun 02 '21 at 12:11
  • The actual problem seems to be `OverloadingPlus` in `OverloadingPlus.h` because both compilation units define it. –  Jun 02 '21 at 12:21
  • @RetiredNinja Updated the question with the error messages – Lera Jun 02 '21 at 12:22
  • 2
    Don't *define* non-inline and non-template functions in header file that you include in multiple translation units. Such functions will be defined in each translation unit, header include guard won't protect you against that. – Some programmer dude Jun 02 '21 at 12:26
  • @jabaa Updated `OverloadingPlus.h` with the header guards. The issues persists with them. – Lera Jun 02 '21 at 12:27
  • Talking about header include guards, your guard names are invalid. All symbols beginning with double underscore (or a single underscore followed by an uppercase letter) are reserved in all scopes. See [What are the rules about using an underscore in a C++ identifier?](https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) – Some programmer dude Jun 02 '21 at 12:28
  • I feel like you're including `OverloadingPlus.h` in more than one file. If you define a function in a header like that it needs to be marked inline. – Retired Ninja Jun 02 '21 at 12:28
  • Sorry about my first (now deleted) comment, misread the code. – Some programmer dude Jun 02 '21 at 12:28
  • Is this your actual code or do you have `#include "OverloadingPlus.h"` in `Complex.cpp` (or another translation unit)? In the latter case this problem is reproducible with GCC and Clang. –  Jun 02 '21 at 12:30
  • @Someprogrammerdude Thanks for the comment. Updated my code and the question with different header guard names. But in this case the problem persists – Lera Jun 02 '21 at 12:35
  • @RetiredNinja Just did a check of all other files to make sure, but `OverloadingPlus.h` is not included anywhere else – Lera Jun 02 '21 at 12:37
  • The problem is the *definition* (implementation) of the `OverloadingPlus` function in a header file. If you include that header file in multiple [*translation units*](https://en.wikipedia.org/wiki/Translation_unit_(programming)) (essentially a source file with all included header files) then you will get the error you get. – Some programmer dude Jun 02 '21 at 12:37
  • @jabaa This is indeed the actual code I have on my VS project – Lera Jun 02 '21 at 12:38
  • 1
    Please include the ***full*** and ***complete*** build output in your question. It should usually include the name of the object file where the second definition is located. – Some programmer dude Jun 02 '21 at 12:39
  • Also please try to mark the function as `inline`. Do you still get the error then? If not then you do indeed include the header file (directly or indirectly) somewhere else. – Some programmer dude Jun 02 '21 at 12:40
  • By the way, are you building with `OverloadingPlus.h` as a *source* file as well as a header file? Where in your MSVC project hierarchy is `OverloadingPlus.h` located? Under `Header Files` or under `Source Files`? – Some programmer dude Jun 02 '21 at 12:42
  • 1
    I just tested it myself in Visual Studio 2019. One cpp file including a header with a function in it. Function isn't marked inline and no include guards. Works fine. I know you've said several times that the header isn't being included more than once, but all evidence points to that. Same result whether the header is in the solution in the Header Files or Source Files filter group. Try adding `/showIncludes` to the C++/Command Line option in the project settings. – Retired Ninja Jun 02 '21 at 12:53
  • @Someprogrammerdude 1. I tried marking the function as inline and it does generates various unresolved externals errors (I will update the question with those) 2. I understand the build output are all the contents generated by VS in the Debug folder of my project, is that right? 3. `OverloadingPlus.h` and `Complex.hpp` are located under `Header Files` while `main.cpp` and `Complex.cpp` are located under `SourceFiles` – Lera Jun 02 '21 at 12:53
  • @Someprogrammerdude Sorry. Missinterpreted your comment about marking the function as inline. Marking `OverloadingPlus()` function as inline does indeed solve the issue. – Lera Jun 02 '21 at 13:06
  • There's a difference between *declaring* a function (telling the compiler the function exists *somewhere* in some translation unit), and *defining* a function (actually implementing it). Multiple declarations are okay, as long as they are all the same. – Some programmer dude Jun 02 '21 at 14:17
  • 1
    @RetiredNinja As you suggested, added /showIncludes and the log file shows OverloadingPlus.h once under main.cpp's includes. Both with OverloadingPlus marked as inline and without marking it as inline. I still can't see where it could've been included twice, but let's assume it did, how could it be that the same error would not be triggered by the operator<< implementation? It should have been defined twice as well, producing the same error, right? – Lera Jun 02 '21 at 14:56
  • @Someprogrammerdude Right, I meant to use definition instead of declaration. – Lera Jun 02 '21 at 14:57

2 Answers2

1

The issue seems to be related to VS2019. Renaming the file to something different, rebuilding the project and renaming the file back to its original name fixed the issue.

While using inline as others suggested did circumvent the issue, it does not solve this specific problem as the conflicting file was not being included multiple times.

Lera
  • 33
  • 1
  • 7
  • Yeah, if you rename something or have other weird problems always Build->Clean. I usually use Build->Batch Build and clean all of the targets at once. Glad you figured it out, it was a weird one. – Retired Ninja Jun 02 '21 at 20:22
  • 1
    @RetiredNinja Really weird indeed. Thank you for the help – Lera Jun 06 '21 at 10:00
0

You forgot to "inline" your OverloadingPlus.

inline void OverloadingPlus() {
    Complex c1(1, 4);
    Complex c2(3, 2);

    std::cout << c1 + c2 << std::endl;
}

should make the linker error go away.

What probably happened is: You have included "OverloadingPlus.h" in more than one compilation unit (although you failed to provide all instances of your #include in your question).

Every time you include "OverloadingPlus.h" in one of your .cpp files, you add another definition for void OverloadingPlus to your program. The linker detects this and cannot decide on "the right one" and so gives an error.

Hajo Kirchhoff
  • 1,969
  • 8
  • 17
  • This does indeed solve the issue. However, the code presented in the question is the actual code that produced this error and there are surely no other includes referencing this file. But, assuming there were multiple `#include "OverloadingPlus.h"` statements across my project, shouldn't the `#ifndef` guard prevent any duplicate declaration? – Lera Jun 02 '21 at 13:39
  • @Lera only within one `.cpp` file. If you have multiple implementation files each will define it – Caleth Jun 02 '21 at 13:41
  • If this solved your problem, then you *definitely* have multiple includes. – Hajo Kirchhoff Jun 02 '21 at 13:45
  • And the ifdef guard does not prevent this. It cannot. Think about it: Each .cpp File gets compiled separately. Each .cpp produces it's own .obj file. The ifdef guard prevents duplicate inclusion only *per cpp file*. IOW: If this one cpp file includes the .h file multiple times (either directly or indirectly via other .h files), the .h file is processed only once. But once the .cpp has been compiled, all ifdef and other macros are moot. They do not carry over to the next .cpp. – Hajo Kirchhoff Jun 02 '21 at 13:47
  • So if file_one.cpp includes it and file_two.cpp also includes it, you end up with two .obj files where the function has been generated. And the linker complains. You might want to read up on "compilation units" and learn a little more about what happens when the compiler generates a .obj file. Perhaps try to compile your files manually with cl.exe – Hajo Kirchhoff Jun 02 '21 at 13:47
  • One more thing. Use ``` #include using Complex = std::complex; ``` rather than our own complex class (unless this is just an exercise :-) std::complex is part of the C++ standard. – Hajo Kirchhoff Jun 02 '21 at 13:51
  • @HajoKirchhoff Yes, this is just an exercise. Clearly the conclusion is that somehow the file is being included more than once, but what can I say when `#include "OverloadingPlus.h"` exists only once (in `main.cpp`), and the include logs show only one instance of `OverloadingPlus.h`.? – Lera Jun 02 '21 at 15:25
  • Glad you figured it out. Although this really is strange. – Hajo Kirchhoff Jun 03 '21 at 11:02