No match for operator+

Hey guys, I'm pretty new to C++ and I'm just doing some uni homework and trying to understand operator overloading. When I try to compile my code though, I get the error message:

"point_test.cpp: In function ‘int main()’:
point_test.cpp:46:115: error: no match for ‘operator+’ (operand types are ‘banfield_lab3::point’ and ‘banfield_lab3::point’)
std::cout << "The sum of " << my_point1.get_point() << " and " << my_point2.get_point() << " is: (" << my_point1 + my_point2 << ")" << std::endl;"

I've done a bit of googling on the topic but I still don't fully understand what I'm doing wrong.

Sorry if the answer is really obvious but any help would be greatly appreciated.

From point.cpp:

1
2
3
4
5
6
7
8
9
10
11
  point operator +(const point& point1, const point& point2){
	//Postcondition: The sum of point1 and point2 is returned
	double x_sum,
		   y_sum;
		   
	x_sum = (point1.get_x() + point2.get_x());
	y_sum = (point1.get_y() + point2.get_y());
	point sum(x_sum + y_sum);
	
	return sum;		   
}


From point_test.cpp:

1
2
3
4

std::cout << "The sum of " << my_point1.get_point() << " and " 
<< my_point2.get_point() << " is: (" << my_point1 + my_point2 << ")" << std::endl;


If needed, I can include my .h file as well as .cpp files.
Is the overload declared in a header visible to point_test.cpp?
@helios Ah, no it wasn't. With that sorted though, another problem arises.

I now get this error message:

"point_test.cpp: In function ‘int main()’:
point_test.cpp:46:102: error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream<char>’ and ‘banfield_lab3::point’)
std::cout << "The sum of " << my_point1.get_point() << " and " << my_point2.get_point() << " is: (" << my_point1 + my_point2 << ")" << std::endl;"

Does this mean I need to convert the operator<< aswell? I already have a function that converts an instance of point to a string to display it.

1
2
3
4
5
6
std::string point::get_point() {
	std::ostringstream strs;
	strs << "(" << point::get_x() << ", " << point::get_y() << ")" << std::endl;
	std::string str = strs.str();
	return str;
}


However, if I try the following code:

1
2
3
4
point my_point4;
	my_point4 = my_point1 + my_point2;
	std::cout << "The sum of " << my_point1.get_point() << " and " 
<< my_point2.get_point() << " is: (" << my_point1 + my_point2 << ")" << std::endl;


I get the following error message:

"point_test.o:point_test.cpp:(.text+0x4f8): undefined reference to `banfield_lab3::operator+(banfield_lab3::point const&, banfield_lab3::point const&)'
point_test.o:point_test.cpp:(.text+0x4f8): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `banfield_lab3::operator+(banfield_lab3::point const&, banfield_lab3::point const&)'
collect2: error: ld returned 1 exit status"

I've done a bit more searching on google but I'm still unsure as to what exactly I'm doing wrong.
You must compile the point.cpp too and include the resulting object file in the linking phase.

The result of mypoint1+my_point2 is a point. Shouldn't you call its get_point()?
@keskiverto I'm pretty sure I am compiling the point.cpp. I don't exactly understand what this all means but this is what my makefile looks like:

CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=point.h point.cpp point_test.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=point_test

all: $(SOURCES) $(EXECUTABLE)

$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $@

%.o : %.cpp
$(CC) $(CFLAGS) -c $<

clean:
rm -rf *.o core


Also, you are right. The piece of code in my reply was meant to be this:

1
2
3
4
point my_point4;
	my_point4 = my_point1 + my_point2;
	std::cout << "The sum of " << my_point1.get_point() << " and " 
<< my_point2.get_point() << " is: (" << my_point4.get_point() << ")" << std::endl;

Remove point.h from the SOURCES.
Remove point.h from the SOURCES.


Not exactly. Point.o and main.o should be rebuilt when point.h changes, and I believe MrPigeon's makefile does this. MrPigeon can test via:
1
2
3
$ make
$ touch point.h
$ make // should rebuild point.o, main.o, and core 


The makefile wouldn't be so great if he had source files that did not depend on point.h, but for this project it should be enough.

I store all of my source files in an src directory ( within the project directory ), and this is the makefile I use:
https://raw.githubusercontent.com/Lowest0ne/make_template/master/makefile
Last edited on
True, not exactly. The problem is that now point.h is in OBJECTS and therefore in the linking command. We don't link headers.

Furthermore, the object files do not depend on the header, so touching the header should trigger only the relinking. Your dynamic dependency calculation creates more elaborate rules.
the object files do not depend on the header, so touching the header should trigger only the relinking.


How about you try this out before disagreeing. If you don't know how, you can start by changing the name of Point to Poynt.
Last edited on
Shouldn't this point sum(x_sum + y_sum); be point sum(x_sum, y_sum);? Though, I suppose you could have some very weird constructor that takes in the x and y as one variable then some how guesses how to extract them from that number.
Lowest0ne wrote:
How about you try this out before disagreeing. If you don't know how, you can start by changing the name of Point to Poynt.
point_test.cpp
1
2
3
4
5
6
#include "point.h"
int main()
{
  foo( 42 );
  return 0;
}

point.h
1
2
3
4
#ifndef DEC_POINT_H
#define DEC_POINT_H
void foo( int );
#endif 

point.cpp
1
2
3
4
5
6
#include <iostream>
#include "point.h"
void foo( int bar )
{
  std::cout << bar << '\n';
}

Makefile.x
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=point.h point.cpp point_test.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=point_test

all: $(SOURCES) $(EXECUTABLE)

$(EXECUTABLE): $(OBJECTS)
        $(CC) $(LDFLAGS) $(OBJECTS) -o $@

%.o : %.cpp
        $(CC) $(CFLAGS) -c $<

clean:
        rm -rf *.o core

$ make -n -f Makefile.x 
g++ -c -Wall -c point.cpp
g++ -c -Wall -c point_test.cpp
g++  point.h point.o point_test.o -o point_test

$ make -f Makefile.x 
g++ -c -Wall -c point.cpp
g++ -c -Wall -c point_test.cpp
g++  point.h point.o point_test.o -o point_test

$ touch point.h
$ make -n -f Makefile.x 
g++  point.h point.o point_test.o -o point_test

$ sed -i s/foo/gaz/ point.h
$ make -n -f Makefile.x 
g++  point.h point.o point_test.o -o point_test

$ make -f Makefile.x 
g++  point.h point.o point_test.o -o point_test
point.h
1
2
3
4
#ifndef DEC_POINT_H
#define DEC_POINT_H
void gaz( int );
#endif 

Apparently the linker does ignore the header files, so having point.h there is merely a cosmetic error.

However, the rule to create object file from .cpp does not have point.h as dependency.
The rule to link objects to point_test does depend on point.h and touching point.h will indeed cause relink of the binary.
Ah, you were right. There was no need for me to have point.h in the sources.

Another mistake I made was that I had the declaration of the overloaded + operator inside the point.cpp file. I've moved that now to inside the point.h file outside the scope of the class.

However, now I get an error message:

"point_test.o:point_test.cpp:(.text+0x0): multiple definition of `banfield_lab3::operator+(banfield_lab3::point, banfield_lab3::point)'
point.o:point.cpp:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status"

I did a bit of searching for what this meant and it seems that by declaring the overloaded operator in the .h file I am violating The One Definition rule. However, after reviewing my lectures notes. This seems to be how my lecturer does it. Is there something I'm missing?

I'm just going to include my entire point.h file for reference:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/*
 * Cale Banfield c3132281@uon.edu.au 28/08/2014
 *
 */

#ifndef POINT_H_
#define POINT_H_
#include <string>

namespace banfield_lab3 {

class point {

public:
    // Constructor

    // Postcondition: A new instance of Point is created and its instance 
    // data initialised to either the origin point on a cartesian plane or   
	// parameter provided value
    
    point(double initialX = 0.0, double initialY = 0.0);

    // Mutator members

    // Precondition: point_coordinateX and Y have been initialised
    // Postcondition: X coordinate is updated
    void set_x(double coordinateX);

    // Precondition: point_coordinateX and Y have been initialised
    // Postcondition: Y coordinate is updated
    void set_y(double coordinateY);

    // Precondition: point_coordinateX and Y have been initialised
    // Postcondition: X and Y coordinates are updated
    void set_point(double coordinateX, double coordinateY);

    // Accessor members

    // Precondition: point_coordinateX and Y have been initialised
    // Postcondition: The coordinate of X is returned    
    double get_x() const;

    // Precondition: point_coordinateX and Y have been initialised
    // Postcondition: The coordinate of y is returned   
    double get_y() const;

    // Precondition: point_coordinateX and Y have been initialised
    // Postcondition: uses cout to output the point using the notation (x, y)
    // with coordinates displayed accurate to 2 decimal places
    std::string get_point();
		
    // Member functions
	
    //Precondition: Two instances of point have been initialised
    //Postcondition: Calculates the length between two points on a Cartesian plane
    double length(const point point1, const point point2);
	
private:
    // Private Variables
    double point_coordinateX;
    double point_coordinateY;
    double length_pnts;
	
};
	
    point operator +(const point point1, const point point2){
    //Postcondition: The sum of point1 and point2 is returned
    double x_sum,
                y_sum;
		   
    x_sum = (point1.get_x() + point2.get_x());
    y_sum = (point1.get_y() + point2.get_y());
    point sum(x_sum + y_sum);
	
    return sum;		   
    }
	
}
	
#endif /* POINT_H_ */ 


@giblit yes you are completely right.
Last edited on
Here is where the make docs tell us to include headers as prerequisites:
http://www.gnu.org/software/make/manual/make.html#Rule-Example

If point.cpp includes the definition, then Line 66 should be a declaration:
point operator+( const point point1, const point point2 );
@LowestOne I see, I confused myself.

Now, I'm back to the problem with the code from point_test.cpp:

1
2
3
4
point my_point4;
my_point4 = my_point1 + my_point2;
std::cout << "The sum of " << my_point1.get_point() << " and " 
<< my_point2.get_point() << " is: (" << my_point4.get_point() << ")" << std::endl;


I get the error message:

"point_test.o:point_test.cpp:(.text+0x4f8): undefined reference to `banfield_lab3::operator+(banfield_lab3::point const&, banfield_lab3::point const&)'
point_test.o:point_test.cpp:(.text+0x4f8): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `banfield_lab3::operator+(banfield_lab3::point const&, banfield_lab3::point const&)'
collect2: error: ld returned 1 exit status"

I know that it's a linker error but I'm still unsure what is going wrong.
I don't disagree about having headers as prerequisities.
What your automatic dependency generation effectively does is an addition of two lines to the OP's makefile:
point.o : point.h

point_test.o : point.h

However, if we write that manually, we may as well write:
$(OBJECTS) : point.h



@MrPigeon
Implementation in *.cpp, declaration in *.h

Think about these:
1
2
3
4
5
6
7
8
9
10
point & point::operator+= ( const point & rhs ) {
  this->point_coordinateX += rhs.point_coordinateX;
  this->point_coordinateY += rhs.point_coordinateY;
  // whatever the this->length_pnts requires
  return *this;
}

point operator+ ( point lhs, const point & rhs ) {
  return lhs += rhs;
}
Topic archived. No new replies allowed.