views:

163

answers:

2

I have a class 'Vector3' which is compiled successfully. It contains both non-friend and friend functions, for example, to overload * and << operators when Vector3 is the second operand. The problem is I can't link to any of the friend functions, be it operator overloaded or not. So I can confirm that the error is not specific to operator overloading. The g++ command used for linking is as follows (please also see Makefile at the end),

g++ -Wall -W -I./ -g -o main.out main.o Vector3.o

which gave the following errors,

main.cpp:7: undefined reference to `operator*(double, Vector3 const&)'
main.cpp:9: undefined reference to `mag(Vector3 const&)'
main.cpp:10: undefined reference to `operator<<(std::basic_ostream<char, std::char_traits<char> >&, Vector3 const&)'

Below is the relevant code in my source files. I follow the practice of making separate .hpp and .cpp for every class.

/* file Vector3.hpp */
struct Vector3 {
    ...
    Vector3 operator*(const double k) const;
    friend Vector3 operator*(const double k, const Vector3 &vec);
    double magnitude() const;
    friend double mag(const Vector3 &vec);
    friend std::ostream& operator<<(std::ostream& output, const Vector3 &vec);
    ...
}

/* file Vector3.cpp */
Vector3 operator*(const double k, const Vector3 &vec) {
    ...
}

inline double mag(const Vector3 &vec) {
    ...
}

std::ostream& operator<<(std::ostream& output, const Vector3 &vec) {
    ...
}

/* file main.cpp */
#include "Vector3.hpp"
int main() {
    Vector3 M(1, 1, 1);
    M = M * 2.0;              // own operator* links successfully
    M = 10.0 * M;             // friend operator* doesn't link
    double m = M.magnitude(); // own function magnitude() links successfully
    double n = mag(M);        // friend function mag() doesn't link
    std::cout << M;           // friend operator<< doesn't link
}

Finally, this is my Makefile.

CXX         = g++
CXXFLAGS    = -Wall -W $(INCPATH) -g
INCPATH     = -I./
OBJS        = main.o Vector3.o

main.out: $(OBJS)
 $(CXX) $(CXXFLAGS) -o $@ $(OBJS) $(LIBPATH)

main.o: main.cpp
Vector3.o: Vector3.cpp

clean:
 rm -f $(OBJS) main.out

The strangest thing is that if I include the Vector3.cpp file as well in main.cpp and then remove Vector3.o from OBJS in Makefile, the program links successfully. I cannot make sense of this. Please help me!!

+1  A: 

The definition of friend operator* uses fp_type while the friend declaration uses double as the first parameter. This will only work as intended if fp_type is a typedef-name for double. Are you sure fp_type actually stands for double? I can't see it from the code you posted.

The problem with mag is rather obvious: you defined it as inline in .cpp file. Inline function definitions have to be visible everywhere they are used, meaning that normally they should be placed in the header file.

AndreyT
Never mind. I found my blunder and will be deleting this question soon :)
Aamir
A: 

Hi Amir,

Can you please share your solution? I'm seeing the same problem:

main.cpp:14: undefined reference to `operator<<(std::basic_ostream >&, ... )

so maybe your solution can help.

Thanks!

Assaf
The solution was as suggested by Andrey. I put the definitions of inline functions in the header file and it worked like a charm!
Aamir
If you are having a related problem, be sure that your cpp file defines the functions in the namespace in which they were declared. This is a common mistake.
Marius