2

I'm trying to overload the << operator on the ostream - class?

For some reason I'm overloading it twice, I can't seem to figure out why cause i have #ifndef in my header file.

matrix.h

#ifndef MATRIX_H
#define MATRIX_H

#include <iostream>

using namespace std;

class matrix {
    int x, y;
    public:
        matrix(int a, int b);
        matrix& operator* (matrix B);

    friend ostream& operator<< (ostream& os, const matrix& A);
};

ostream& operator<< (ostream& os, const matrix& A)
{
    os << "Matrix.....";
    return os;
}

#endif

matrix.cpp

#include <iostream>
#include "matrix.h"

matrix::matrix(int a, int b) {

}
matrix& matrix::operator* (matrix B) {

}

and main.cpp

#include <iostream>
#include "matrix.h"

using namespace std;

int main () {
    matrix a(6, 6), b(6, 6);

    cout << a;

    return 0;
}

I am building like this:

$ cat build.sh 
g++ -c main.cpp
g++ -c matrix.cpp

g++ -g -o main main.o matrix.o

The build error I am getting is:

$bash build.sh 
ld: duplicate symbol operator<<(std::basic_ostream<char, std::char_traits<char> >&, matrix const&)in matrix.o and main.o for architecture x86_64
collect2: ld returned 1 exit status

Think this is strait forward but I can't seem to find the solution.

Thanks for your time.


g++ -v

$g++ -v
...skipped 4 lines...
gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.1.00)
Andreas Louv
  • 46,145
  • 13
  • 104
  • 123

1 Answers1

10

You are defining a function with external linkage and including it in two compilation units.

I would advocate just adding an inline keyword to your function definition, or moving the function definition inside the class.

What does this do?

By adding a non-static free function like your operator<< you define a function with external linkage, which means that it causes an entry in the generated object files' symbol tables.

If the function is inline or template, the compiler/linker must handle this e.g. by simply picking an arbitrary one. (This is OK, because the ODR causes them to be equivalent.)

If, however this is not the case (as in your example), this causes a linker error, since the linker does not know which one you meant.

You could also (or even additionally) declare your function to be static, which would cause it to lose external linkage (gaining internal linkage instead), which is just a fancy way of saying that it does not generate a symbol table entry. This will cause this function to be compiled into a new version for every compilation unit that includes your header, and is therefore inferior to the other solutions.

But the define guard?

Only prevents the function to be defined multiple times in one compilation unit.

OK, list all my options!

First, you could utilize a property of friend functions and define it in the class (which effectively causes it to gain the inline keyword as defined in C++ 11.3/7):

class matrix {
    int x, y;
public:
    matrix(int a, int b);
    matrix& operator* (matrix B);

    friend ostream& operator<< (ostream& os, const matrix& A)
    {
        os << "Matrix.....";
        return os;
    }
};

Alternatively, you could cause it to be an inline function by adding inline in front of it.

You may sometimes see both of these techniques combined: A friend function that is defined inside a class and also annotated with inline. The inline is completely superfluous in that case and does not change anything.

You may also cause it to gain internal linkage by either adding the static keyword to it, or wrapping it inside an unnamed namespace. While this would solve the problem, it will cause unnecessary bloat, since every compilation unit that includes this function will have its very own internal copy. Technically internal linkage can be combined with inline.

Trying to make a template function out of this, while technically possible, is a lot of work and does not really gain you anything above the other solutions. It would solve your problem, though, leading to a variant very akin to the inline version.

As a last option, you can move the function definition into a single compilation unit (read: .cpp file). The matrix.cpp file is certainly volunteering, since it holds function relating to your matrix class anyway.

Community
  • 1
  • 1
danielschemmel
  • 10,885
  • 1
  • 36
  • 58
  • 1
    The other alternatives are to move the definition inside the class definition, or into a source file. – Mike Seymour May 15 '13 at 17:55
  • 1
    `static` is probably a bad idea: the program will probably be bloated with multiple copies, and you might get obscure bugs if there are any static variables, or if anything depends on the address of the function. – Mike Seymour May 15 '13 at 18:01
  • 1
    Given the function's triviality, `inline` would be preferred to moving it into a source file. – Mike DeSimone May 15 '13 at 18:02
  • @MikeSeymour `static` and unnamed namespaces were primarily added to explain the problem that causes the error. – danielschemmel May 15 '13 at 18:09
  • 1
    @dionadar: No they weren't. They were added to allow you to declare a name within one translation unit without clashing with the same name declared (for a different purpose) in other translation units. `inline` was added for this situation, to allow you to define the same function in multiple translation units *without* duplicating the function when linking. – Mike Seymour May 15 '13 at 18:12
  • I was talking about my answer, not the reasoning behind internal linkage in general. – danielschemmel May 15 '13 at 18:15
  • @dionadar: Sorry, I misunderstood. Either way, the answer reads to me as if it's suggesting `static` as a way to fix the problem, which would be bad advice. – Mike Seymour May 15 '13 at 18:19
  • I made it a bit more explicit, to ensure that it is clear that `static` although a possible fix for the problem is not the best solution. – danielschemmel May 15 '13 at 18:32