Overloading an external operator

3

I am overloading the operator + externally. It is obvious that if I put:

Fraccion operator+ (const Fraccion& r1, const Fraccion& r2)
{
  Fraccion res;

  res.numerador = r1.obtenerNum() + r2.obtenerNum();
  res.denominador = r1.obtenerDen() + r2.obtenerDen();
  return res;
}

res.numerador and res.denominador are not accessible as they are private members and could only be called through a public function that returns them, but if I use this:

Fraccion operator+ (const Fraccion& r1, const Fraccion& r2)
{
  Fraccion res;

  res.obtenerNum() = r1.obtenerNum() + r2.obtenerNum();
  res.obtenerDen() = r1.obtenerNum() + r2.obtenerDen();
  return res;
}

The compiler tells me that it is not assignable. It is clear that if this same thing I do overloading as a member function yes that would be worth (the first overloaded function that I put you with members res.numerador ) But then how should I put those variables so that they can access a value with that external overloaded function?

Thank you!

I attach the Fraction class (invented by me):

class Fraccion
{
public:
  Fraccion(float n=0, float d=0) : numerador(n), denominador(d) {}
  //Operador = OBLIGATORIA como función interna a la clase
  Fraccion& operator=(const Fraccion& frac);
  Fraccion& operator-(const Fraccion& frac2);
  void mostrarFraccion() const;
  void rellenarFraccion();
  float obtenerNum() const { return numerador; }
  float obtenerDen() const { return denominador; }
private:
  float numerador;
  float denominador;
};
    
asked by ProgrammerJr 27.03.2018 в 12:34
source

2 answers

3
Fraccion operator+ (const Fraccion& r1, const Fraccion& r2)
{
    Fraccion res;

    res.obtenerNum() = r1.obtenerNum() + r2.obtenerNum();
    res.obtenerDen() = r1.obtenerNum() + r2.obtenerDen();
    return res;
}
     

The compiler tells me it is not assignable.

And it's logical, if we look at the implementation:

float obtenerNum() const { return numerador; }
float obtenerDen() const { return denominador; }

We see that both obtenerNum and obtenerDen return a VLD (value on the right side RValue in English ). VLDs are a category of data that is expected to always be to the right of an operator and therefore can not be used to the left of an operator (see this thread for more details).

You could modify obtenerNum and obtenerDen to return a VLI (value on the left side):

const &float &obtenerNum() const { return numerador; }
//    ~ <--- Obtiene una referencia al dato interno
const &float &obtenerDen() const { return denominador; }
//    ~ <--- Obtiene una referencia al dato interno
float &obtenerNum() { return numerador; }
//    ~ <--- Obtiene una referencia al dato interno
float &obtenerDen() { return denominador; }
//    ~ <--- Obtiene una referencia al dato interno

But you will need the constant and non-constant versions, it is a common practice (note the operator at of std::vector ).

This way your free operator is already functional:

Fraccion operator+ (const Fraccion& r1, const Fraccion& r2)
{
    // res no es constante
    Fraccion res;

    res.obtenerNum() = r1.obtenerNum() + r2.obtenerNum();
//  ~~~ <--- llama a la versión no-constante de Fraccion::obtenerNum
    res.obtenerDen() = r1.obtenerNum() + r2.obtenerDen();
//  ~~~ <--- llama a la versión no-constante de Fraccion::obtenerDen
    return res;
}

But this code is rather confusing, take advantage that you have a constructor that receives numerator and denominator to build your Fraccion object when you return it and take advantage of optimization of return value :

Fraccion operator+ (const Fraccion& r1, const Fraccion& r2)
{
    return { r1.obtenerNum() + r2.obtenerNum(), r1.obtenerNum() + r2.obtenerDen() };
}

The code is much simpler that way. Of course you can also use a friend function as suggested by Trauma .

    
answered by 27.03.2018 / 12:55
source
3

Make your function friend of your class:

class Fraccion
{
  friend operator+( const Fraccion &, const Fraccion & );

public:
  Fraccion(float n=0, float d=0) : numerador(n), denominador(d) {}
  //Operador = OBLIGATORIA como función interna a la clase
  Fraccion& operator=(const Fraccion& frac);
  Fraccion& operator-(const Fraccion& frac2);
  void mostrarFraccion() const;
  void rellenarFraccion();
  float obtenerNum() const { return numerador; }
  float obtenerDen() const { return denominador; }
private:
  float numerador;
  float denominador;
};

By declaring it friend , you allow the functions or class to access members private and public .

    
answered by 27.03.2018 в 12:41