Sobrecarga de operador << solo me compila si uso la palabra "friend"

Iniciado por digimikeh, 13 Febrero 2019, 04:44 AM

0 Miembros y 1 Visitante están viendo este tema.

digimikeh

Buenas amigos..

Tenía entendido que la palabra reservada "friend" permitía acceder a todas mis variables privadas de mi clase desde fuera, es como una excepción a la regla, para friend sería todo publico.

He querido utilizar el operador sobrecargado << para que mi clase pueda ser impresa por la salida estándar.

Esto es lo que tengo:

Código (cpp) [Seleccionar]

//Persona.h
#include <iostream>

class Persona{

    char * nombre;
    int edad;

public:

    Persona();
    ~Persona();
   
    //La siguiente linea da error si no coloco la palabra friend al principio
    std::ostream & operator<<(std::ostream & os, Persona & _estaPersona);
    char * LeerNombre() const;
    int LeerEdad() const;
     void InsertarNombre(const char * _nuevoNombre);
     void InsertarEdad(const int _nuevaEdad);

};



Código (cpp) [Seleccionar]

//Persona.cpp

#include "Persona.h"

using namespace std;

//Sobrecarga operador
ostring & operator<<(ostring & os, const Persona & _estaPersona){
    os << "Nombre : " << _estaPersona.LeerNombre() << endl;
    os << "Edad     : " << _estaPersona.LeerEdad() << endl;
    return os;
}

char * Persona::LeerNombre(){
    return nombre;
}

int Persona::LeerEdad(){
    return edad;
}

void Persona::InsertarNombre(const char * _nuevoNombre){
    strcpy(nombre, _nuevoNombre);
}

void Persona::InsertarEdad(const int _nuevaEdad){
    edad = _nuevaEdad;
}



Código (cpp) [Seleccionar]

//main.cpp
#include Persona.h

int main (){
    Persona p;
    p.InsertarNombre("ElHacker");
    p.Edad(37);
   
    std::cout << p << endl;
}


Lo que no entiendo, es que según la definición de friend, esto no me calza, yo no quiero acceder desde fuera a una propiedad privada, solo estoy intentando acceder a LeerNombre() y LeerEdad() que son publicas, no debería necesitar colocar friend... es que acaso friend con el operador trabaja de forma distinta?

Gracias de antemano.
Dungeons & dragons;
dragons.Attack();

K-YreX

Este es un error típico con la sobrecarga tanto del operador << como del operador >>.
Ambas sobrecargas son funciones, no métodos. Un método de una clase puede acceder a los miembros privados por si sólo porque en eso consiste un método, en una función que pertenece a una clase.

Sin embargo, esa sobrecarga es una función, no un método. Entonces el prototipo de la función debe definirse fuera de la clase. Y la implementación de la función si se hace en un fichero distinto se hace sin referenciar la clase a la que pertenece (ya que no pertenece a ninguna).

Y cuando queremos hacer que una función sea "friend" entonces el prototipo lo incluimos dentro de la clase precedido de la palabra <friend> pero si no se usa la palabra <friend> entonces hay que declararlo fuera de la clase.

Código (cpp) [Seleccionar]

class MiClase{
    private:
        // miembros y metodos privados
    public:
        // miembros y metodos publicos
        // Opcion 1: sobrecarga con friend
        friend std::ostream& operator<<(ostream&, const MiClase&);
};
// Opcion 2: sobrecarga sin friend
std::ostream& operator<<(ostream&, const MiClase&);


Espero haber resuelto tus dudas respecto a este tema. Suerte :-X

PD: He visto un extraño <ostring> en tu código... :silbar:
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

digimikeh

entnoces no era obligación meter la palabra "friend", sabía!.. no me hacía sentido, simplemente tenía que declarar y definir fuera de la clase esta sobrecarga ....

He usado también la sobrecarga == y ésta sí que se comporta como yo esperaba dentro de la clase, por lo visto no todos los operadores se sobrecargan de la misma forma verdad?.

Estuve observando el ostream que mencionas, pero por mas que veo, se me pasa el error, no lo veo, en qué linea está ?..

Saludos y gracias.
Dungeons & dragons;
dragons.Attack();

CalgaryCorpus

Para los operadores, considera el tipo que esta a la izquierda del operador. Son distintos cuando usas << y cuando usas ==

ostream << clase

clase == clase

Donde defines la funcion o metodo, depende del tipo de la izquierda del operador.

El primero de ellos se define fuera de la clase, el segundo dentro de la misma.

Los metodos al interior de la clase no necesitan especificar el operando de la izquierda del operador, pues se sobreentiende que se trata del objeto donde se ejecuta el metodo. Solo requieren especificar 1 parametro, el de la derecha del operador.

Cuando pones la firma de la funcion dentro de la clase, sin poner friend, el compilador te va reclamar no porque no pusiste "friend", te va a reclamar porque al ponerla dentro de la clase, es un metodo como el resto y el operator<< solo puede recibir 1 parametro y le estas pasando 2.

Aqui mi perfil en LinkedIn, invitame un cafe aqui

K-YreX

Cita de: digimikeh en 13 Febrero 2019, 13:38 PM
Estuve observando el ostream que mencionas, pero por mas que veo, se me pasa el error, no lo veo, en qué linea está ?..

En tu fichero Persona.cpp en la declaración de la sobrecarga del operador <<. Y si lo quieres ver en el primer mensaje de este tema, el segundo bloque de código:
Cita de: digimikeh en 13 Febrero 2019, 04:44 AM
Código (cpp) [Seleccionar]

//Persona.cpp

#include "Persona.h"

using namespace std;

//Sobrecarga operador
ostring & operator<<(ostring & os, const Persona & _estaPersona){
     os << "Nombre : " << _estaPersona.LeerNombre() << endl;
     os << "Edad     : " << _estaPersona.LeerEdad() << endl;
     return os;
}
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

Loretz

La sobrecarga del operador << suele hacerse de dos maneras (típicamente); si necesita acceder a miembros privados o protegidos de la clase, será una función friend; si no lo necesita, se prefiere una función libre. (Más, te diría que siempre que existe la alternativa, se prefieren funciones libres a funciones miembro).

No quisiera entrar en controversias personales, pero... sobre la afirmación de YreX-DwX:
CitarAmbas sobrecargas son funciones, no métodos.

Es muy frecuente usar la palabra "método" para referirse a funciones miembro de alguna clase, pero que sea un uso común no quiere decir que sea la forma correcta, y menos que sea obligatorio. El estándar C++ las llama "member function", y los que no hablamos inglés, por comodidad les decimos "funciones miembro", claro que también alguien puede decirles "procedimientos", "métodos", o cosas así, pero es sólo por comodidad, no porque así deba decirse. (Prueba: ponte a buscar las distintas ocurrencias de la palabra "method" en el documento del estándar y verás que en ningún caso se aplica a funciones, a ningún tipo).

Por otro lado:
void Persona::InsertarNombre(const char * _nuevoNombre){
     strcpy(nombre, _nuevoNombre);
}

Aquí tienes un problema, "nombre" no tiene memoria asignada (con new, por ejemplo), es un puntero que apunta a quién sabe donde, de modo que lo esperable es que strcpy haga un destrozo.


digimikeh

Si, @Loretz , lo que esperaria ahí es Segment fault 11... tienes razon, aunque lo escribi a la rapida para mostrar mi problema de ostream mas que nada...  :laugh:

@Yrex-DwX ya me di cuenta que con ostring no sacaba nada jajha
Dungeons & dragons;
dragons.Attack();