Overload of error operator

Asked

Viewed 56 times

-1

The code below is with the following error:

Error:

[Error] invalid operands of types 'Ponteiro*' and 'Ponteiro*' to binary 'operator+'

Code:

#include <iostream>

using namespace std;

class Ponteiro{
    public:
        int x;
        int y;
        void valores(int _x = 0, int _y = 0);   
        int soma();
        void operator + (Ponteiro* p);
};

void Ponteiro::valores(int _x, int _y){
    this->x = _x;
    this->y = _y;
}

int Ponteiro::soma(){
    return this->x + this->y; 
}

void Ponteiro::operator +(Ponteiro* p){
    this->x += p->x;
    this->y += p->y;
}

int main() {
    
    Ponteiro* pt = new Ponteiro();
    pt->valores(1,2);
    
    Ponteiro* pt2 = new Ponteiro();
    pt2->valores(3, 4);

    pt = pt + pt2;
            
}

Why doesn’t Overload work? is pointer conflict?

2 answers

4

You have a good explanation above, but I’ll show you another example, perhaps more complete.

Your class is called Ponteiro probably not the best option. whereas she has two int x and y maybe you could use it to represent a Ponto as the classical structure (C)

typedef struct _COORD {
  SHORT X;
  SHORT Y;
} COORD, *PCOORD;

used by Windows to address pixels, where x is the column and y the line.

What is valores()?

    void Ponto::valores(int _x, int _y)
    {
        this->x = _x;
        this->y = _y;
    }

This is only a possible constructor of the class. You should not create a function. Make it simple:

   Ponto::Ponto(int _x, int _y)
   {
        x = _x;
        y = _y;
   }

Which is usually written like this:

    Ponto::Ponto(int x, int y) : x(x), y(y) {};

because it’s simpler and easier to read. And always set the default constructor, which has no arguments. In the example below I will do the simple and leave the pattern as (0,0).

And you don’t have to write those this all the time. C++ is not java

What is soma()?

    int Ponto::soma() { return this->x + this->y; }

Note that you can write like this on a line only when you find it readable.

Yet I imagine that’s what you want to turn into operator+

And then there’s a problem (maybe). Much of the advantage of redefining such an operator is to be able to operate with them as in an expression, just as it does with

    int a = 42;
    int b = 600;
    int c = a + b;

be able to write

    Ponto a(10,10);
    Ponto b(1, 2);
 
    Ponto c = a + b;

and have c.x = 11 and c.y = 12 and be able to use expressions such as a + b + c + d where there are 4 Ponto.

To do this you must understand the polymorphism and the fact that + will represent a sum after all. And the + b should return what? Not a int, but a new Ponto. Sure, you can have both. That’s polymorphism. But the relevant thing is to have the sum of two Ponto generating a Ponto.

And you must use references, not pointers. And of course the sum does not change the plots so you must declare the plots const& thus

Ponto operator+ (const Ponto& A, const Ponto& B)
{
    return Ponto(A.x + B.x, A.y + B.y);
}

And understand that Operator+ is not part of the class, it can be a free Function

Overloading <<

A common convenience would be to reset shift to left --- << --- for a Ponto, as it is common to redefine toString() in java and I’ll leave an example here because I think it makes sense. So you can use cout << ponto and have centralized control over what will show on the screen. So this code in main()

    Ponto A = Ponto(-3,-4); 
    cout << A << endl;

    Ponto B = Ponto(2, 3);
    cout << A << " + " << B << " = " << A + B << endl;

    Ponto P = Ponto(); // vai ser criado (0,0)
    cout << "Padrao: " << P << endl;

showcase

(-3,-4)
(-3,-4) + (2,3) = (-1,-1)
Padrao: (0,0)

And I think you can see that it’s very readable. Of course you would normally need to implement a lot more operators, but the idea is the same always.

The example has a class Ponto and an archive main.cpp

Point. h

#pragma once
#include <iostream>
using namespace std;
class Ponto
{
public:
    int x; // coluna
    int y;

public:
    Ponto(int, int);
    Ponto(); // construtor padrao

    friend ostream& operator<< (ostream&, const Ponto&);
    friend Ponto operator+ (const Ponto& A, const Ponto& B);
};

Point.cpp

#include "Ponto.h"

Ponto::Ponto(int x, int y) : x(x), y(y) {};
Ponto::Ponto() : Ponto(0,0) {}; // padrao

ostream& operator<< (ostream& fluxo, const Ponto& p)
{
    fluxo << "(" << p.x << "," << p.y << ")";
    return fluxo;
}

Ponto operator+ (const Ponto& A, const Ponto& B)
{
    return Ponto(A.x + B.x, A.y + B.y);
}

main.cpp

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

int main(void)
{
    Ponto A = Ponto(-3,-4); 
    cout << A << endl;

    Ponto B = Ponto(2, 3);
    cout << A << " + " << B << " = " << A + B << endl;

    Ponto P = Ponto(); // vai ser criado (0,0)
    cout << "Padrao: " << P << endl;
    return 0;
}

Note that normally x and y would be defined as private Thus declaring, code that uses the class has no access to the fields of Ponto: only through class functions. This is the concept of encapsulation. So I declared the functions that implement the operators as friend, as an example of what you would need to do. With the fields x and y declared public no need to use friend: All are friends :)

1

That standard you adopted for the Overload pointer got a little confused.

The method has been implemented for the class Ponteiro, which means you can only use it for an instance of Ponteiro, but in your code you’re trying to use it for an instance of Ponteiro*, which is not the same thing.

So the value that should be received to the right of the operator is a Ponteiro*, that is, that Overload can only add guys Ponteiro with Ponteiro*.

To use your implementation, you would first need to de-reference pt and add it to pt2:

(*pt) + pt2;

Detail that the return of this operation is void, then you cannot assign the result to pt. The fact that the operator is changing the value of pt instead of returning a new value is also a strange pattern.

Traditionally the Overload of + is done by receiving a structure (not a pointer) and returning a structure of the same type:

Ponteiro Ponteiro::operator +(Ponteiro p) {
    return Ponteiro {
        .x = this->x + p.x,
        .y = this->y + p.y,
    };
}

That way it would make sense to write the code the way you asked the question... except for the point that you should be declaring these structures in the stack, rather than allocating them in the heap with the operator new:

int main() {
    
    Ponteiro pt;
    pt.valores(1,2);
    
    Ponteiro pt2;
    pt2.valores(3, 4);

    pt = pt + pt2;
    cout << pt.x << "\n";
    cout << pt.y << endl;

}

Note: nothing in this code is actually a pointer, so maybe it makes sense to give another name to its structure Ponteiro.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.