Autor Tema: C++ cplusplus --> Modificar operadores igual distinto <<, == y != Crear clases  (Leído 5693 veces)

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Hola compis, estoy inciándome con C++, haciendo cosicas en modo consola y tal...

Se me ha propuesto el siguiente ejercicio. El enunciado está en inglés pero no creo que requiera traducción:

Citar
2. Design and implement a Name_pairs class holding (name,age) pairs where name is a string and age is a double.
Represent that as a vector<string> (called name) and a vector<double> (called age) member.
 Provide an input operation read_names() that reads a series of names.
 Provide a read_ages() operation that prompts the user for an age for each name.
 Provide a print() operation that prints out the (name,age) pairs (one per line) in the orderdetermined by the name vector.
 Provide a sort() operation that sorts the name vector in alphabetical order and reorganizes the age vector to match.
 Implement all “operations” as member functions.

Ok, esto lo puedo hacer sin demasiado problema. Pongo el código a continuación.
Si alguien quiere compilarlo, necesitará esta librería: std_lib_facilities.h

Código: [Seleccionar]
#include "..\..\..\..\lib\std_lib_facilities.h"

namespace Nombres {
class Name_pairs
{
public:
void read_names();
void read_ages();
void print();
void sort();
private:
vector <string> name;
vector <double> age;
};

void Name_pairs::read_names()
{
string nombre;
do
{
cout << "\nIntroduzca nombre(*=FIN): ";
cin >> nombre;
if (nombre != "*") name.push_back(nombre);

} while (nombre != "*");
}

void Name_pairs::read_ages()
{
int t = name.size();
double edad;
if (t == 0)
{
cout << "\nPrimero hay que introducir nombres...\n";
}
else
{
for (int i = 0; i < t; i++)
{
cout << "\nIntroduzca la edad de: " << name[i] << " --> ";
cin >> edad;
age.push_back(edad);
}
}
}


void Name_pairs::print()
{
int t = name.size();
if (t == 0)
{
cout << "\nNo hay datos que mostrar.\n";
}
else
{
for (int i = 0; i < t; i++)
{
cout << "\nNombre: " << name[i] << " Edad: " << age[i];
}
}
}

void Name_pairs::sort()
{
int t = name.size();
if (t == 0)
{
cout << "\nNo hay datos que ordenar.\n";
}
else
{
vector <string> name_temp;
vector <double> age_temp;
for (int i = 0; i < t; i++)
{
name_temp.push_back(name[i]);
age_temp.push_back(age[i]);
}

std::sort(name.begin(), name.end());//Recalco que este sort() pertenece a std, y no a mi clase Name_pairs.

//Busca coincidencias entre los vectores de nombres original y ordenado para "copiar" el mismo orden en el vector de edad.
//Esta funcion podria ser errónea si hubieran nombres repetidos en el vector.
for (int i = 0; i < t; i++)
{
for (int j = 0; j < t; j++)
{
if (name_temp[i] == name[j]) age[j] = age_temp[i];
}
}
}

}
}//namespace Nombres

int main()
{
using namespace Nombres;

cout << system("cls");
Name_pairs listado;

listado.read_names();
listado.read_ages();
listado.print();
listado.sort();
listado.print();
cout << endl;

return 0;
}

Todo esto compila bien y compruebo con un pequeño main()  que todo furrula: pide nombres hasta meter un asterisco, puego pide edades para cada nombre, luego los muestra, los ordena alfabéticamente, ordena también el vector edades según se ordenó el vector de nombres y vuelve a mostrarlos tras los cambios.

Ahora viene la segunda parte, que es la que se me atraganta:
Citar
3. Replace Name_pair::print() with a (global) operator << and define == and != for Name_pairs.*/

Bien, de momento solo he intentado hacer que el operador << haga lo que hace print().... pero no lo consigo.

En print(), lo primero que hago es obtener el tamaño del vector de nombres, para comprobar si hay algo que mostrar y si lo hay, pues lo uso para el contador del bucle.

Intento hacer lo mismo en la funcion donde modifico el operador << , pero me da error pues no reconoce el vector name.
Código: [Seleccionar]
/*
//Sustituimos esta funcion con la siguiente donde modificamos el operador <<
void Name_pairs::print()
{
int t = name.size();
if (t == 0)
{
cout << "\nNo hay datos que mostrar.\n";
}
else
{
for (int i = 0; i < t; i++)
{
cout << "\nNombre: " << name[i] << " Edad: " << age[i];
}
}
}*/

ostream& operator<<(ostream& os, const Name_pairs& np)
{
int t = name.size();

                //Falta código por escribir....

}

Vale, tiene sentido, pues no indico a que objeto me refiero y tal.
Pruebo a dar un palo de ciego con esto, que no se por qué, ya imaginaba que tampoco iba a servir:
Código: [Seleccionar]
ostream& operator<<(ostream& os, const Name_pairs& np)
{
int t = np.name.size();

                //Falta código por escribir....

}

Y me digo, pues oye, hacemos una nueva funcion en public: que devuelva el tamaño del vector. Que además, es un dato que estoy necesitando en el resto de funciones.

Código: [Seleccionar]
namespace Nombres {
class Name_pairs
{
public:
void read_names();
void read_ages();
void sort();
int name_size();//devuelve el tamaño del vector de nombres
private:
vector <string> name;
vector <double> age;
};

int Name_pairs::name_size()
{
return name.size();
}

[.....]

ostream& operator<<(ostream& os, const Name_pairs& np)
{
int t = np.name_size();
                 
                //Falta código por escribir....

}

Y nada, tampoco furrula, obtengo estos errores al compilar:

Citar
Error   C2662   'int Nombres::Name_pairs::name_size(void)': no se puede convertir el puntero 'this' de 'const Nombres::Name_pairs' a 'Nombres::Name_pairs &'   235_03   e:\programación\c++\consola\libro\235_03\235_03\235_03.cpp   81


Error (activo)      el objeto tiene calificadores de tipo que no son compatibles con la función "Nombres::Name_pairs::name_size" miembro   235_03   e:\Programación\C++\Consola\Libro\235_03\235_03\235_03.cpp   81

Y me he quedado sin ideas....
Si el parámetro np se supone que representa un objeto de clase Name_pairs, ¿donde está el problema? ¿Qué hago mal?

Espero haberme explicado más o menos claro, a ver si podeis guiarme...
Gracias por adelantado
« Última modificación: 24 de Septiembre 2015, 12:30 por César Krall »
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re:C++ --> Modificar operador <<
« Respuesta #1 en: 22 de Septiembre 2015, 11:05 »
Buaahh!!!... Apenas acabo de publicar mi duda, ya he hallado solución..

En la función donde modifico el operador, lo que hago es pasar np a una variable temporal de tipo Name_Pairs y ahora ya si me permite acceder a las funciones definidas en la clase.
Citar
void operator<<(ostream& os, const Name_pairs& np)
   {
      Name_pairs temp = np;
      int t = temp.name_size();
      if (t == 0)
      {
         cout << "\nNo hay datos que mostrar.\n";
      }
      else
      {
         for (int i = 0; i < t; i++)
         {
            cout << "\nNombre: " << temp.get_names() << " Edad: " << temp.get_ages();
         }
      }

   }
Además he corregido la definición de esta función indicando que es de tipo void ya que no va a devolver ningún valor.
Para acceder a los vectores nombre y edad, lo hago a través de dos nuevas funciones: get_names() y get_ages() que antes no tenía, pero que ahora ya si he puesto en public:
Citar
class Name_pairs
   {
   public:
      void read_names();
      void read_ages();
      //void print();
      void sort();
      int name_size();//devuelve el tamaño del vector de nombres
      vector <string> get_names() { return name; }
      vector <double> get_ages() { return age; }
   private:
      vector <string> name;
      vector <double> age;
   };

Y con todo esto, ya no necesito la fucnión print() para mostrar el contenido de los vectores, ahora lo hace el operador << el solito.

Nome cabe duda de que aquí alguien me podría haber ayudado, si le hubiera dado tiempo je je... es curioso que me atasqué cone sto hace un apr de días.. y cuando por fin me decido a pedir ayuda... a los cinco minutos se me enciende la bombilla con la solución.
Gracias igualmente a todo el mundo por hacer posible este foro.

Os dejo como queda el código final:
Código: [Seleccionar]
#include "..\..\..\..\lib\std_lib_facilities.h"

namespace Nombres {
class Name_pairs
{
public:
void read_names();
void read_ages();
void sort();
int name_size();//devuelve el tamaño del vector de nombres
vector <string> get_names() { return name; }
vector <double> get_ages() { return age; }
private:
vector <string> name;
vector <double> age;
};


int Name_pairs::name_size()
{
return name.size();
}

void Name_pairs::read_names()
{
string nombre;
do
{
cout << "\nIntroduza nombre(*=FIN): ";
cin >> nombre;
if (nombre != "*") name.push_back(nombre);

} while (nombre != "*");
}

void Name_pairs::read_ages()
{
int t = name.size();
double edad;
if (t == 0)
{
cout << "\nPrimero hay que introducir nombres...\n";
}
else
{
for (int i = 0; i < t; i++)
{
cout << "\nIntroduzca la edad de: " << name[i] << " --> ";
cin >> edad;
age.push_back(edad);
}
}
}

void operator<<(ostream& os, const Name_pairs& np)
{
Name_pairs temp = np;
int t = temp.name_size();
if (t == 0)
{
cout << "\nNo hay datos que mostrar.\n";
}
else
{
for (int i = 0; i < t; i++)
{
cout << "\nNombre: " << temp.get_names()[i] << " Edad: " << temp.get_ages()[i];
}
}

}

void Name_pairs::sort()
{
int t = name.size();
if (t == 0)
{
cout << "\nNo hay datos que ordenar.\n";
}
else
{
vector <string> name_temp;
vector <double> age_temp;
for (int i = 0; i < t; i++)
{
name_temp.push_back(name[i]);
age_temp.push_back(age[i]);
}

std::sort(name.begin(), name.end());

//Busca coincidencias entre los vectores de nombres original y ordenado para "copiar" el mismo orden en el vector de edad.
//Esta funcion podria ser errónea si hubieran nombres repetidos en el vector.
for (int i = 0; i < t; i++)
{
for (int j = 0; j < t; j++)
{
if (name_temp[i] == name[j]) age[j] = age_temp[i];
}
}
}

}
}//namespace Nombres

int main()
{
using namespace Nombres;

cout << system("cls");
Name_pairs listado;

listado.read_names();
listado.read_ages();
cout << listado;
listado.sort();
cout << listado;
cout << endl;

return 0;
}
« Última modificación: 24 de Septiembre 2015, 10:42 por César Krall »
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re:C++ --> Modificar operador <<[¡¡Solucionado!!]
« Respuesta #2 en: 22 de Septiembre 2015, 12:14 »
Añado las funciones que faltaban para cumplir el enunciado, es decir, modificar los operadores de comparacion == y != para que sepa como comparar correctamente dos objetos del tipo Name_pairs.
Ambas funciones son idénticas, solo cambian los valores que devuelven.

De nuevo he tenido que pasar los objetos que recibo como parámetros (a y b) a unas variables/objeto temporales (aa y bb). ¿Por qué no puedo operar directamente con a y b?

Código: [Seleccionar]
bool operator==(const Name_pairs& a, const Name_pairs& b)
{
Name_pairs aa = a;
Name_pairs bb = b;

if (aa.name_size() != bb.name_size()) return false;//Si los vectores tienen distintos tamaños, los objetos no pueden ser iguales
for (int i = 0; i < aa.name_size(); i++)//Recorremos vectores para comparar sus contenidos
{
if (aa.get_names()[i] != bb.get_names()[i]) return false;//Si algun nombre no coincide, se acabó, no son iguales
else if (aa.get_ages()[i] != bb.get_ages()[i]) return false;//Si alguna edad no coincide, se acabó, no son iguales
}

return true;//Si hemos llegado a esta línea, es que vectores son del mismo tamaño y sus elementos coinciden, así que son iguales
}

bool operator!=(const Name_pairs& a, const Name_pairs& b)
{
Name_pairs aa = a;
Name_pairs bb = b;

if (aa.name_size() != bb.name_size()) return true;
for (int i = 0; i < aa.name_size(); i++)
{
if (aa.get_names()[i] != bb.get_names()[i]) return true;
else if (aa.get_ages()[i] != bb.get_ages()[i]) return true;
}

return false;
}
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

César Krall

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 2078
  • No vales por lo que dices, sino por lo que haces
    • Ver Perfil
    • aprenderaprogramar.com
Re:C++ cplusplus --> Modificar operadores igual distinto <<, == y != Crear clases
« Respuesta #3 en: 24 de Septiembre 2015, 10:56 »
Hola Kabuto! Muy curioso lo que comentas que después de varios días dándole vueltas justo después de consultar sea cuando se te ocurriera la solución :) Gracias por dejar la solución, le puede servir de ayuda a otras personas.

Lo que comentas

Citar
De nuevo he tenido que pasar los objetos que recibo como parámetros (a y b) a unas variables/objeto temporales (aa y bb). ¿Por qué no puedo operar directamente con a y b?

También es curioso, la única diferencia que veo entre a y aa es que a está afectada por const mientras que aa no lo está

Saludos!
Responsable de departamento de producción aprenderaprogramar.com

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re:C++ cplusplus --> Modificar operadores igual distinto <<, == y != Crear clases
« Respuesta #4 en: 24 de Septiembre 2015, 12:15 »

También es curioso, la única diferencia que veo entre a y aa es que a está afectada por const mientras que aa no lo está

Saludos!

Hola César. Efectivamente eso que mencionas es la clave.

La funciones (métodos) de la clase : name_size(), get_names(), get_ages() no las declaré como constantes.

Pero luego en las funciones donde modifico los operadores de comparacion y output, ahí los objetos que paso como parametros a, b y np sí los recojo como constantes, entonces por eso el compilador me ponía pegas al querer aplicarles métodos no constantes.
Si hago copia de ellos en objetos "temporales" no constantes, entonces ya no me pone pegas, que es la solución que encontré, pero para nada es la óptima.

Ahora que ya he entendido el problema, me ha bastado con añadir const a las declaraciones de los métodos y así ya puedo prescindir de tener que hacer copias temporales de los objetos que recojo como parámetro.

Y mira que ya había leído anteriormente una advertencia sobre esto de aplicar métodos no constantes a objetos constantes....pero hasta que no metes la pata y te tienes que calentar la cabeza, pues no lo aprendes je je...

Os dejo abajo el código final, con otro main() adaptadado para comprobar que funcionan las modificaciones a los operadores de comparación.
Os recuerdo enlace para descargar la std_lib_facilities.h y poder compilarlo. Me parece que el que puse en el primer mensaje no funciona.


Por cierto, muy potente esto de poder "enseñar" a los operadores como mostrar, recoger y comparar los objetos de nuestras clases. Como mola ir aprendiendo estas cosillas...

Un saludo y pronto volveré por aquí, con una docena de dudas más jeje...

Código: [Seleccionar]
#include "..\..\..\..\lib\std_lib_facilities.h"

namespace Nombres {
class Name_pairs
{
public:
void read_names();
void read_ages();
void sort();
int name_size() const { return name.size(); }
vector <string> get_names() const { return name; }
vector <double> get_ages() const { return age; }
private:
vector <string> name;
vector <double> age;
};

void Name_pairs::read_names()
{
string nombre;
do
{
cout << "\nIntroduza nombre(*=FIN): ";
cin >> nombre;
if (nombre != "*") name.push_back(nombre);

} while (nombre != "*");
}

void Name_pairs::read_ages()
{
int t = name.size();
double edad;
if (t == 0)
{
cout << "\nPrimero hay que introducir nombres...\n";
}
else
{
for (int i = 0; i < t; i++)
{
cout << "\nIntroduzca la edad de: " << name[i] << " --> ";
cin >> edad;
age.push_back(edad);
}
}
}

void operator<<(ostream& os, const Name_pairs& np)
{
int t = np.name_size();
if (t == 0)
{
cout << "\nNo hay datos que mostrar.\n";
}
else
{
for (int i = 0; i < t; i++)
{
cout << "\nNombre: " << np.get_names()[i] << " Edad: " << np.get_ages()[i];
}
}

}

bool operator==(const Name_pairs& a, const Name_pairs& b)
{
if (a.name_size() != b.name_size()) return false;//Si los vectores tienen distintos tamaños, los objetos no pueden ser iguales
for (int i = 0; i < a.name_size(); i++)//Recorremos vectores para comparar sus contenidos
{
if (a.get_names()[i] != b.get_names()[i]) return false;//Si algun nombre no coincide, se acabó, no son iguales
else if (a.get_ages()[i] != b.get_ages()[i]) return false;//Si alguna edad no coincide, se acabó, no son iguales
}

return true;//Si hemos llegado a esta línea, es que vectores son del mismo tamaño y sus elementos coinciden, así que son iguales
}

bool operator!=(const Name_pairs& a, const Name_pairs& b)
{
if (a.name_size() != b.name_size()) return true;
for (int i = 0; i < a.name_size(); i++)
{
if (a.get_names()[i] != b.get_names()[i]) return true;
else if (a.get_ages()[i] != b.get_ages()[i]) return true;
}

return false;
}

void Name_pairs::sort()
{
int t = name.size();
if (t == 0)
{
cout << "\nNo hay datos que ordenar.\n";
}
else
{
vector <string> name_temp;
vector <double> age_temp;
for (int i = 0; i < t; i++)
{
name_temp.push_back(name[i]);
age_temp.push_back(age[i]);
}

std::sort(name.begin(), name.end());

//Busca coincidencias entre los vectores de nombres original y ordenado para "copiar" el mismo orden en el vector de edad.
//Esta funcion podria ser errónea si hubieran nombres repetidos en el vector.
for (int i = 0; i < t; i++)
{
for (int j = 0; j < t; j++)
{
if (name_temp[i] == name[j]) age[j] = age_temp[i];
}
}
}

}
}//namespace Nombres

int main()
{
using namespace Nombres;

cout << system("cls");
Name_pairs listado, listado2;

listado.read_names();
listado.read_ages();
listado2 = listado;
cout << "\nSe ha hecho copia del listado, en listado2\n";
cout << "Antes de ordenar listado...";
cout << "\nlistado == listado2 --> ";
if (listado == listado2) cout << "Cierto.\n";
else cout << "Falso.\n";
cout << "\nlistado != listado2 --> ";
if (listado != listado2) cout << "Cierto.\n";
else cout << "Falso.\n";
cout << endl;
listado.sort();
cout << "Despues de ordenar listado...";
cout << "\nlistado == listado2 --> ";
if (listado == listado2) cout << "Cierto.\n";
else cout << "Falso.\n";
cout << "\nlistado != listado2 --> ";
if (listado != listado2) cout << "Cierto.\n";
else cout << "Falso.\n";
cout << endl;

return 0;
}
« Última modificación: 24 de Septiembre 2015, 12:22 por Kabuto »
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

César Krall

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 2078
  • No vales por lo que dices, sino por lo que haces
    • Ver Perfil
    • aprenderaprogramar.com
Re:C++ cplusplus --> Modificar operadores igual distinto <<, == y != Crear clases
« Respuesta #5 en: 24 de Septiembre 2015, 12:32 »
Como dices el enlace que habías puesto no funcionaba, pero he aprovechado y he editado el post de modo que ya funciona. Gracias por las aportaciones, muy interesantes!
Responsable de departamento de producción aprenderaprogramar.com

 

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".