Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - xaps

#81
Cita de: amchacon en 16 Diciembre 2013, 18:07 PM
char es un dato número, es como si fuera un int de 1 byte.
No hay ningún problema mientras la clase que use tenga definido los operadores correspondientes (+ - * / ==...).

O al menos tenga definido los operadores de las funciones que vaya a usar.
Pues me he puesto a estudiar y implementar los templates en la clase, pero me he encontrado con un problema que no me deja avanzar. La mayoría de mis sobrecargas de operadores son funciones amigas de la función, y por lo visto en general hay problemas al implementar los templates con funciones amigas. No sé si por suerte o por desgracia, la única función que parece no encajar bien con los templates es la de sobrecarga del producto. A ver si me podéis ayudar con esto, que llevo un buen rato peleándome con el error buscando, moviendo y cambiando código... Pero no lo consigo.

Vuelvo a pegar el código entero de la clase (ya que se han tenido que cambiar bastantes cosas) y el mensaje de error que estoy recibiendo:

Matriz.h:
Código (cpp) [Seleccionar]
#include <iostream>

using namespace std;

template <class T>
class Matriz {

private:
 
 int nfilas;
 int ncolumnas;
 T **matr = NULL;
 
 void borrar();

public:

 //Constructora
 Matriz(int filas, int columnas);
 
 //Constructora-copiadora
 Matriz(const Matriz<T> &m);
 
 //Destructora
 ~Matriz();
 
 //Consultoras
 int filas() const;
 int columnas() const;
 T consultar(int fila, int columna) const;
 
 //Modificadora
 void modificar(int fila, int columna, T x);
 
 //Operadores
 Matriz& operator =(const Matriz<T> &b);
 
 void operator +=(const Matriz<T> &mat);
 void operator -=(const Matriz<T> &mat);
 
 friend Matriz operator + <>(const Matriz<T> &a, const Matriz<T> &b);
 friend Matriz operator - <>(const Matriz<T> &a, const Matriz<T> &b);
 friend Matriz operator * <>(const Matriz<T> &a, const Matriz<T> &b);
 friend Matriz operator * <>(const Matriz<T> &a, int b);
 friend Matriz operator * <>(int a, const Matriz<T> &b);
 
 friend bool operator == <>(const Matriz<T> &a, const Matriz<T> &b);
 friend bool operator != <>(const Matriz<T> &a, const Matriz<T> &b);
 
 friend ostream& operator << <>(ostream &salida, const Matriz<T> &mat);
 friend istream& operator >> <>(istream &entrada, Matriz<T> &mat);
};

template <class T>
Matriz<T>::Matriz(int filas = 0, int columnas = 0) : nfilas(filas), ncolumnas(columnas)
{
 if (nfilas > 0 and ncolumnas > 0)
 {
   matr = new T* [filas];
   for (int i = 0; i < filas; ++i) matr[i] = new T [columnas];
 }
}

template <class T>
Matriz<T>::Matriz(const Matriz<T> &m) { *this = m; }

template <class T>
Matriz<T>::~Matriz() { borrar(); }

template <class T>
void Matriz<T>::borrar()
{
 if (this->matr != NULL)
 {
   for (int i = 0; i < nfilas; ++i) delete[] matr[i];
   delete[] matr;
   matr = NULL;
 }
}

template <class T>
int Matriz<T>::filas() const { return nfilas;}

template <class T>
int Matriz<T>::columnas() const { return ncolumnas;}

template <class T>
T Matriz<T>::consultar(int fila, int columna) const { return matr[fila][columna];}

template <class T>
void Matriz<T>::modificar(int fila, int columna, T x) { matr[fila][columna] = x;}

template <class T>
Matriz<T>& Matriz<T>::operator =(const Matriz<T> &mat)
{
 if (this != &mat)
 {
   this->borrar();

   if (mat.matr)
   {
     this->nfilas = mat.nfilas;
     this->ncolumnas = mat.ncolumnas;
     
     this->matr = new int* [nfilas];
     for (int i = 0; i < nfilas; ++i)
this->matr[i] = new int [ncolumnas];
     
     for (int i = 0; i < nfilas; ++i)
     {
for (int j = 0; j < ncolumnas; ++j)
 this->matr[i][j] = mat.matr[i][j];
     }
   }
 }
 return *this;
}

template <class T>
void Matriz<T>::operator +=(const Matriz<T> &mat)
{
 if (this->nfilas != 0 and this->ncolumnas != 0 and mat.nfilas != 0 and mat.ncolumnas != 0)
 {
   for (int i = 0; i < nfilas; ++i)
     for (int j = 0; j < ncolumnas; ++j)
this->matr[i][j] += mat.matr[i][j];
 }
}

template <class T>
void Matriz<T>::operator -=(const Matriz<T> &mat)
{
 if (this->nfilas != 0 and this->ncolumnas != 0 and mat.nfilas != 0 and mat.ncolumnas != 0)
 {
   for (int i = 0; i < nfilas; ++i)
     for (int j = 0; j < ncolumnas; ++j)
this->matr[i][j] -= mat.matr[i][j];
 }
}

template <class T>
Matriz<T> operator +(const Matriz<T> &a, const Matriz<T> &b)
{
 int filas = a.nfilas;
 int columnas = a.ncolumnas;
 
 Matriz<T> res(filas, columnas);
 
 for (int i = 0; i < filas; ++i)
   for (int j = 0; j < columnas; ++j)
     res.matr[i][j] = a.matr[i][j] + b.matr[i][j];
   
 return res;
}

template <class T>
Matriz<T> operator -(const Matriz<T> &a, const Matriz<T> &b)
{
 int filas = a.nfilas;
 int columnas = a.ncolumnas;
 
 Matriz<T> res(filas, columnas);
 
 for (int i = 0; i < filas; ++i)
   for (int j = 0; j < columnas; ++j)
     res.matr[i][j] = a.matr[i][j] - b.matr[i][j];
   
 return res;
}

template <class T>
Matriz<T> operator *(const Matriz<T> &a, const Matriz<T> &b)
{
 if (a.ncolumnas == b.nfilas)
 {
   int pos = a.ncolumnas;
   
   int filas = a.nfilas;
   int columnas = b.ncolumnas;
   
   Matriz<T> res(filas, columnas);
   for (int i = 0; i < filas; ++i)
   {
     for (int j = 0; j < columnas; ++j)
     {
int value = 0;
for (int k = 0; k < pos; ++k) value += a.matr[i][k] * b.matr[k][j];
res.matr[i][j] = value;
     }
   }
   return res;
 }
}

template <class T>
Matriz<T> operator *(const Matriz<T> &a, int b)
{
 int filas = a.nfilas;
 int columnas = a.ncolumnas;
 
 Matriz<T> res(filas, columnas);
 for (int i = 0; i < filas; ++i)
   for (int j = 0; j < columnas; ++j) res.matr[i][j] = a.matr[i][j] * b;
 
 return res;
}

template <class T>
Matriz<T> operator *(int a, const Matriz<T> &b) { return b*a; }

template <class T>
bool operator ==(const Matriz<T> &a, const Matriz<T> &b)
{
 if (a.nfilas != b.nfilas or a.ncolumnas != b.ncolumnas) return false;
 for (int i = 0; i < a.nfilas; ++i)
   for (int j = 0; j < a.ncolumnas; ++j)
     if (a.matr[i][j] != b.matr[i][j]) return false;
 
 return true;
}

template <class T>
bool operator !=(const Matriz<T> &a, const Matriz<T> &b) { return !(a == b); }

template <class T>
ostream& operator <<(ostream &salida, const Matriz<T> &mat)
{
 for (int i = 0; i < mat.nfilas; ++i)
 {
   for (int j = 0; j < mat.ncolumnas; ++j) salida << mat.matr[i][j] << " ";
   salida << endl;
 }
 return salida;
}

template <class T>
istream& operator >>(istream &entrada, Matriz<T> &mat)
{
 for (int i = 0; i < mat.nfilas; ++i)
   for (int j = 0; j < mat.ncolumnas; ++j) entrada >> mat.matr[i][j];
 return entrada;
}


Y el error que recibo al compilar la clase es el siguiente:
Matriz.h:43:26: error: declaration of 'operator*' as non-function
Matriz.h:43:26: error: expected ';' at end of member declaration
Matriz.h:43:28: error: expected unqualified-id before '<' token
Matriz.h:44:26: error: declaration of 'operator*' as non-function
Matriz.h:44:26: error: expected ';' at end of member declaration
Matriz.h:44:28: error: expected unqualified-id before '<' token
Matriz.h:45:26: error: declaration of 'operator*' as non-function
Matriz.h:45:26: error: expected ';' at end of member declaration
Matriz.h:45:28: error: expected unqualified-id before '<' token


Como podéis ver he añadido "<>" al final del nombre de cada función amiga de la clase, ya que buscando solución a un problema anterior he visto que la mayoría de códigos implementaban esa metodología para las funciones amigas de la clase. Hay más información sobre ésto aquí: http://c.conclase.net/curso/?cap=040c#042_amigaplantilla
Tampoco descarto que os encontréis alguna que otra barbaridad con los templates :silbar:

Gracias por la ayuda! ^^
#82
Cita de: amchacon en 16 Diciembre 2013, 17:12 PM
Dividir 2 matrices es multiplicar por su inversa.
Cierto, no se en que estaría pensando.

Cita de: amchacon en 16 Diciembre 2013, 17:12 PM
Quizás deberías plantearte hacerlo todo a double (o mejor aún, hazlo en formato plantilla y que el usuario decida).
Estaba pensando en usar los templates, pero entonces tengo el problema de que a alguien se le ocurra declarar una matriz de un tipo que no sea numérico, como char o alguna clase no genérica. ¿Que se puede hacer en estos casos? He visto que se pueden hacer especializaciones, pero es imposible hacer una especialización para cada tipo de dato que considere no válido para mi matriz :S
#83
Cita de: amchacon en 16 Diciembre 2013, 15:54 PM
Código (cpp) [Seleccionar]
bool operator ==(const Matriz &a, const Matriz &b)
{
if (a.nfilas != b.nfilas or a.ncolumnas != b.ncolumnas) return false;
for (int i = 0; i < a.nfilas; ++i)
   for (int j = 0; j < a.ncolumnas; ++j)
     if (a.matr[i][j] != b.matr[i][j]) return false;

return true;
}

bool operator !=(const Matriz &a, const Matriz &b)
{
if (a.nfilas != b.nfilas or a.ncolumnas != b.ncolumnas) return true;
for (int i = 0; i < a.nfilas; ++i)
   for (int j = 0; j < a.ncolumnas; ++j)
     if (a.matr[i][j] != b.matr[i][j]) return true;

return false;
}


Esas líneas se pueden reducir a:

Código (cpp) [Seleccionar]
bool operator ==(const Matriz &a, const Matriz &b)
{
if (a.nfilas != b.nfilas or a.ncolumnas != b.ncolumnas) return false;
for (int i = 0; i < a.nfilas; ++i)
   for (int j = 0; j < a.ncolumnas; ++j)
     if (a.matr[i][j] != b.matr[i][j]) return false;

return true;
}

bool operator !=(const Matriz &a, const Matriz &b)
{
return !(a == b);
}

Cierto. Aún no estoy muy acostumbrado a reciclar código...  :silbar:

Cita de: amchacon en 16 Diciembre 2013, 15:54 PM
Te falta por añadir los determinantes (para una matriz nxn).
Para cálculo de determinantes el mejor método es Laplace, ¿verdad?

Cita de: amchacon en 16 Diciembre 2013, 15:54 PM
Y los operadores *= y /= (este ultimo con números enteros).
Cierto. Aunque la división no la he implementado por dos razones:
- La primera, nunca he dividido dos matrices. Supongo que no debe usarse demasiado o que no lo he necesitado de momento.
- La segunda, el hecho de que esté trabajando con enteros hace que la mayoría de divisiones sean inválidas.

Debería cambiar el tipo numérico de la matriz a float para poder realizar divisiones, ¿no? Ya que para escalonar y hacer Gauss probablemente necesite dividir según que posiciones de la matriz.
#84
Cita de: amchacon en 16 Diciembre 2013, 09:32 AM
Es verdad, no había caído en eso.

Aunque solo modificarías la primera.
En realidad no me refería a eso (para eso no hace falta recurrir a C++11). Yo me refería a:

Código (cpp) [Seleccionar]
class Matriz
{
 int ** matr = NULL;
 //...
}


Como ves, lo que inicializo es el mismo atributo de la clase. Así no tengo que ponerlo en todos los constructores.

Vaya, creía que te referías a lo otro que había añadido... Creo que he querido ir demasiado rápido al implementarlo y he lo he hecho con lo primero que he encontrado  :silbar: Aunque tampoco me ha ido mal ^^

Pero bueno, me ha parecido buena idea también y lo he incorporado a la clase, aunque solo lo he hecho con el parámetro matr, ya que he considerado mejor que los otros dos parámetros los deje por defecto en el constructor y que se asignen a la vez que se crea una nueva instancia del objeto.

Esta vez he hecho bastantes más cambios. He añadido los operadores +=, -=, >>(istream) y << (ostream), por lo que he eliminado las funciones leer() y escribir().  También he añadido el producto de una matriz por un escalar y he intentado simular la propiedad de conmutatividad, aunque no se si lo he hecho de la forma correcta. También he cambiado la mayoría de sobrecargas y las he hecho amigas de la clase, de manera que sean externas y no usen el parámetro implícito, ya que me parecía un poco feo utilizar solo el parámetro implícito como consulta pudiendo poner las funciones como amigas de la clase. También he arreglado un par de cosas que podían hacer petar el programa y he probado todas las funciones un poco por encima.

Aquí el código de la clase y del programa que estoy usando para hacer las pruebas:

Matriz.h:
Código (cpp) [Seleccionar]
#include <iostream>

using namespace std;

class Matriz {

private:
 
  int nfilas;
  int ncolumnas;
  int **matr = NULL;
 
  void borrar();

public:

  //Constructora
  Matriz(int filas, int columnas);
 
  //Constructora-copiadora
  Matriz(const Matriz& m);
 
  //Destructora
  ~Matriz();
 
  //Consultoras
  int filas() const;
  int columnas() const;
  int consultar(int fila, int columna) const;
 
  //Modificadora
  void modificar(int fila, int columna, int x);
 
  //Operadores
  Matriz& operator =(const Matriz &b);
 
  void operator +=(const Matriz &mat);
  void operator -=(const Matriz &mat);
 
  friend Matriz operator +(const Matriz &a, const Matriz &b);
  friend Matriz operator -(const Matriz &a, const Matriz &b);
  friend Matriz operator *(const Matriz &a, const Matriz &b);
  friend Matriz operator *(const Matriz &a, int b);
  friend Matriz operator *(int a, const Matriz &b);
 
  friend bool operator ==(const Matriz &a, const Matriz &b);
  friend bool operator !=(const Matriz &a, const Matriz &b);
 
  friend ostream& operator <<(ostream &salida, const Matriz &mat);
  friend istream& operator >>(istream &entrada, Matriz &mat);
};

Matriz::Matriz(int filas = 0, int columnas = 0) : nfilas(filas), ncolumnas(columnas)
{
  if (nfilas > 0 and ncolumnas > 0)
  {
    matr = new int* [filas];
    for (int i = 0; i < filas; ++i) matr[i] = new int [columnas];
  }
}

Matriz::Matriz(const Matriz &m) { *this = m; }

Matriz::~Matriz() { borrar(); }

void Matriz::borrar()
{
  if (this->matr != NULL)
  {
    for (int i = 0; i < nfilas; ++i) delete[] matr[i];
    delete[] matr;
    matr = NULL;
  }
}

int Matriz::filas() const { return nfilas;}

int Matriz::columnas() const { return ncolumnas;}

int Matriz::consultar(int fila, int columna) const { return matr[fila][columna];}

void Matriz::modificar(int fila, int columna, int x) { matr[fila][columna] = x;}

Matriz& Matriz::operator =(const Matriz &mat)
{
  if (this != &mat)
  {
    this->borrar();

    if (mat.matr)
    {
      this->nfilas = mat.nfilas;
      this->ncolumnas = mat.ncolumnas;
     
      this->matr = new int* [nfilas];
      for (int i = 0; i < nfilas; ++i)
this->matr[i] = new int [ncolumnas];
     
      for (int i = 0; i < nfilas; ++i)
      {
for (int j = 0; j < ncolumnas; ++j)
  this->matr[i][j] = mat.matr[i][j];
      }
    }
  }
  return *this;
}

void Matriz::operator +=(const Matriz &mat)
{
  if (this->nfilas != 0 and this->ncolumnas != 0 and mat.nfilas != 0 and mat.ncolumnas != 0)
  {
    for (int i = 0; i < nfilas; ++i)
      for (int j = 0; j < ncolumnas; ++j)
this->matr[i][j] += mat.matr[i][j];
  }
}

void Matriz::operator -=(const Matriz &mat)
{
  if (this->nfilas != 0 and this->ncolumnas != 0 and mat.nfilas != 0 and mat.ncolumnas != 0)
  {
    for (int i = 0; i < nfilas; ++i)
      for (int j = 0; j < ncolumnas; ++j)
this->matr[i][j] -= mat.matr[i][j];
  }
}

Matriz operator +(const Matriz &a, const Matriz &b)
{
  int filas = a.nfilas;
  int columnas = a.ncolumnas;
 
  Matriz res(filas, columnas);
 
  for (int i = 0; i < filas; ++i)
    for (int j = 0; j < columnas; ++j)
      res.matr[i][j] = a.matr[i][j] + b.matr[i][j];
   
  return res;
}

Matriz operator -(const Matriz &a, const Matriz &b)
{
  int filas = a.nfilas;
  int columnas = a.ncolumnas;
 
  Matriz res(filas, columnas);
 
  for (int i = 0; i < filas; ++i)
    for (int j = 0; j < columnas; ++j)
      res.matr[i][j] = a.matr[i][j] - b.matr[i][j];
   
  return res;
}

Matriz operator *(const Matriz &a, const Matriz &b)
{
  if (a.ncolumnas == b.nfilas)
  {
    int pos = a.ncolumnas;
   
    int filas = a.nfilas;
    int columnas = b.ncolumnas;
   
    Matriz res(filas, columnas);
    for (int i = 0; i < filas; ++i)
    {
      for (int j = 0; j < columnas; ++j)
      {
int value = 0;
for (int k = 0; k < pos; ++k) value += a.matr[i][k] * b.matr[k][j];
res.matr[i][j] = value;
      }
    }
    return res;
  }
}

Matriz operator *(const Matriz &a, int b)
{
  int filas = a.nfilas;
  int columnas = a.ncolumnas;
 
  Matriz res(filas, columnas);
  for (int i = 0; i < filas; ++i)
    for (int j = 0; j < columnas; ++j) res.matr[i][j] = a.matr[i][j] * b;
 
  return res;
}

Matriz operator *(int a, const Matriz &b) { return operator*(b, a); }

bool operator ==(const Matriz &a, const Matriz &b)
{
  if (a.nfilas != b.nfilas or a.ncolumnas != b.ncolumnas) return false;
  for (int i = 0; i < a.nfilas; ++i)
    for (int j = 0; j < a.ncolumnas; ++j)
      if (a.matr[i][j] != b.matr[i][j]) return false;
 
  return true;
}

bool operator !=(const Matriz &a, const Matriz &b)
{
  if (a.nfilas != b.nfilas or a.ncolumnas != b.ncolumnas) return true;
  for (int i = 0; i < a.nfilas; ++i)
    for (int j = 0; j < a.ncolumnas; ++j)
      if (a.matr[i][j] != b.matr[i][j]) return true;
 
  return false;
}

ostream& operator <<(ostream &salida, const Matriz &mat)
{
  for (int i = 0; i < mat.nfilas; ++i)
  {
    for (int j = 0; j < mat.ncolumnas; ++j) salida << mat.matr[i][j] << " ";
    salida << endl;
  }
  return salida;
}

istream& operator >>(istream &entrada, Matriz &mat)
{
  for (int i = 0; i < mat.nfilas; ++i)
    for (int j = 0; j < mat.ncolumnas; ++j) entrada >> mat.matr[i][j];
  return entrada;
}


test.cpp:
Código (cpp) [Seleccionar]
#include "Matriz.h"

int main()
{
  int f1, c1, f2, c2;

  cout << "Introduce el tamaño de la primera matriz:" << endl;
  cin >> f1 >> c1;
  Matriz mat1(f1, c1);
  cout << "Introduce los valores de la matriz:" << endl;
  cin >> mat1;
 
  cout << "Introduce el tamaño de la segunda matriz:" << endl;
  cin >> f2 >> c2;
  Matriz mat2(f2, c2);
  cout << "Introduce los valores de la matriz:" << endl;
  cin >> mat2;

 
  if (c1 == f2)
  {
    Matriz res;
    res = mat1 * mat2;
    cout << res << endl;
   
    res = mat1 + mat2;
    cout << res << endl;
   
    res = mat1 - mat2;
    cout << res << endl;
   
    res = res * 4;
    cout << res << endl;
   
    res = 2 * res;
    cout << res << endl;
   
    res += mat1;
    cout << res << endl;
   
    res -= mat2;
    cout << res << endl;
   
    if (res == mat1) cout << "Igualdad incorrecta" << endl;
    else cout << "Igualdad correcta" << endl;
    if (res != mat1) cout << "Desigualdad correcta" << endl;
    else cout << "Desigualdad incorrecta" << endl;
  }
}


¿Que te va pareciendo el código? ¿Crees que hay algo que mejorar o que añadirle? Tengo pensado añadir Gauss a la clase para escalonar y resolver sistemas, pero antes quiero tener la parte más básica bien hecha para luego no tener tantos problemas ^^

Gracias por la ayuda!
#85
Programación General / Re: Duda Java
16 Diciembre 2013, 03:05 AM
Creo entender que estás hablando de cuadros de texto, es decir, interfaz gráfica. Te recomiendo que antes de ponerte a hacer programas con interfaz gráfica te dediques a estudiar el lenguaje y realizar pruebas mediante consola, y cuando ésto ya lo tengas dominado ya podrías pasar a desarrollar programas con interfaz gráfica.

Por cierto, este tema debería ir en el subforo de Java. Tenlo en cuenta para la próxima vez.

Saludos.
#86
1. No hagas dos temas distintos a la vez. Haz las dos preguntas en el mismo tema.
2. Subforo equivocado.
3. Título impreciso.
4. Aquí no se hacen los deberes a nadie.

Si quieres que se te ayude, primero haz tu parte. Y ésta empieza por leerte las reglas:
http://foro.elhacker.net/programacion_general/reglas_subforo_de_programacion_general-t93852.0.html

Siento ser brusco, pero me parece vergonzoso pedir que te hagan los deberes sin ni siquiera mostrar un mínimo interés por tu parte.

Saludos.
#87
Cita de: amchacon en 15 Diciembre 2013, 22:08 PM
Esa sentencia funcionaría exactamente igual con referencias, además sería muchísimo más eficiente (no tienes que estar copiando, creando nuevos objetos, borrando...).
Pero si lo hiciera por referencias estaría modificado las matrices que estoy sumando, ¿no?

Cita de: amchacon en 15 Diciembre 2013, 22:08 PM
De hecho yo me definiría y usaría el operador +=, que eso siempre va a ser más eficiente que hacer dos por separado (+ y =).
La verdad, no se me había ocurrido, pero me parece buena idea añadirlo, además de que tengo pendiente sobrecargar los operadores << y >> de iostream para la entrada/salida de datos. También pensé en los operadores ++ y --, pero no les veo utilidad para matrices.

Cita de: amchacon en 15 Diciembre 2013, 22:08 PM
En C++11 puedes inicializar una variable por defecto en una clase. De formas que no tienes que estar matr = NULL en todos los constructores xD
Voy a investigar sobre esto, parece bastante interesante. Muchas gracias ^^

EDITO: He modificado la constructora añadiendo los valores por defecto y gracias a esto he conseguido ahorrarme la constructora que tenía sin parámetros ^^ Aquí el código:

Código (cpp) [Seleccionar]

Matriz::Matriz(int filas = 0, int columnas = 0) : nfilas(filas), ncolumnas(columnas)
{
 if (nfilas > 0 and ncolumnas > 0)
 {
   matr = new int* [filas];
   for (int i = 0; i < filas; ++i)
   {
     matr[i] = new int [columnas];
   }
 }
 else matr = NULL;
}


También he modificado la constructora para que modifique los parámetros de la clase antes del propio código. Según he leído, esto sirve para inicializar objetos de otras clases usando sus constructores y no los por defecto, pero ésto no se podía hacer de otra manera también? Es decir, ¿estos dos códigos no harían lo mismo?

Código (cpp) [Seleccionar]

Clase1::Clase1(Clase2 obj) : parametro1(clase2) {}

Código (cpp) [Seleccionar]

Clase1::Clase1(Clase2 obj)
{
 parametro1 = Clase1 (obj);
}


Gracias! ^^
#88
Cita de: amchacon en 15 Diciembre 2013, 17:55 PM
Vale fallo mío, creía que el operador + era para sumar la misma matriz. Pero por lo que veo genera otra matriz nueva  :silbar:

Para eso te recomiendo que uses una función, un operador se supone que es para hacer una operación en un objeto (no para generar otros).

Lo hago más que nada para poder realizar operaciones del tipo:
Matriz m1, m2, m3, m4;
m1 = m2 + m3 + m4;


Es decir, como si fuera un entero o cualquier otro tipo. Pero gracias por la recomendación ^^

Al final he conseguido arreglar la función borrar() a modo de prueba y error, y he averiguado varias cosas:
- Cuando haces delete a un puntero, éste se queda apuntando a la dirección de memoria que lo hacia antes y no pasa a valer NULL.
- La contructora-copiadora que me has pasado tenia un pequeño fallo que me ha hecho pasarme, literalmente, horas a base de prueba y error hasta ver que era lo que estaba ocurriendo (que no te lo estoy echando en cara, todo lo contrario, me ha ayudado a comprender mejor el funcionamiento de POO y te estoy agradecido ^^). Al ser una constructora, había que inicializar el puntero matr a NULL porque si no, cuando hagamos la asignación dentro de la constructora, en la función borrar intentará eliminar unas posiciones de memoria que no son propias del programa, ya que la condición if (this->matr != NULL) la pasaba.

Seguramente me deje alguna cosilla más que quería comentar, si me acuerdo de algo nuevo editaré este comentario ^^ Os adjunto el código de la clase (funciona como mínimo para multiplicar y asignar, falta ver el resto de funciones):

Código (cpp) [Seleccionar]

#include <iostream>
#include <vector>

using namespace std;

class Matriz {

private:
 
 int nfilas;
 int ncolumnas;
 int **matr;
 
 void borrar();

public:

 //Constructoras
 Matriz();
 Matriz(int filas, int columnas);
 
 //Constructora-copiadora
 Matriz(const Matriz& m);
 
 //Destructora
 ~Matriz();
 
 //Consultoras
 int filas() const;
 int columnas() const;
 int consultar(int fila, int columna) const;
 
 //Modificadora
 void modificar(int fila, int columna, int x);
 
 //Entrada / Sortida
 void leer();
 void escribir() const;
 
 //Operadores
 Matriz& operator =(const Matriz &b);
 
 Matriz operator +(const Matriz &b) const;
 Matriz operator -(const Matriz &b) const;
 Matriz operator *(const Matriz &b) const;
 
 bool operator ==(const Matriz &mat) const;
 bool operator !=(const Matriz &mat) const;
};

Matriz::Matriz()
{
 nfilas = 0;
 ncolumnas = 0;
 matr = NULL;
}

Matriz::Matriz(int filas, int columnas)
{
 this->nfilas = filas;
 this->ncolumnas = columnas;
 
 if (nfilas > 0 and ncolumnas > 0)
 {
   matr = new int* [filas];
   for (int i = 0; i < filas; ++i)
   {
     matr[i] = new int [columnas];
   }
 }
 else
 {
   nfilas = 0;
   ncolumnas = 0;
   matr = NULL;
 }
}

Matriz::Matriz(const Matriz &m)
{
 this->matr = NULL;
 *this = m;
}

Matriz::~Matriz() { borrar(); }

void Matriz::borrar()
{
 if (this->matr != NULL)
 {
   for (int i = 0; i < nfilas; ++i) delete[] matr[i];
   delete[] matr;
   matr = NULL;
 }
}

int Matriz::filas() const { return nfilas;}

int Matriz::columnas() const { return ncolumnas;}

int Matriz::consultar(int fila, int columna) const { return matr[fila][columna];}

void Matriz::modificar(int fila, int columna, int x) { matr[fila][columna] = x;}

void Matriz::leer()
{
 for (int i = 0; i < nfilas; ++i)
   for (int j = 0; j < ncolumnas; ++j) cin >> matr[i][j];
}

void Matriz::escribir() const
{
 for (int i = 0; i < nfilas; ++i)
 {
   for (int j = 0; j < ncolumnas; ++j) cout << matr[i][j] << " ";
   cout << endl;
 }
}

Matriz& Matriz::operator =(const Matriz &mat)
{
 if (this != &mat)
 {
   this->borrar();

   if (mat.matr)
   {
     this->nfilas = mat.nfilas;
     this->ncolumnas = mat.ncolumnas;
     
     this->matr = new int* [nfilas];
     for (int i = 0; i < nfilas; ++i)
this->matr[i] = new int [ncolumnas];
     
     for (int i = 0; i < nfilas; ++i)
     {
for (int j = 0; j < ncolumnas; ++j)
 this->matr[i][j] = mat.matr[i][j];
     }
   }
 }
 return *this;
}

Matriz Matriz::operator +(const Matriz &b) const
{
 int filas = this->nfilas;
 int columnas = this->ncolumnas;
 
 Matriz res(filas, columnas);
 
 for (int i = 0; i < filas; ++i)
   for (int j = 0; j < columnas; ++j)
     res.matr[i][j] = this->matr[i][j] + b.matr[i][j];
   
 return res;
}

Matriz Matriz::operator -(const Matriz &b) const
{
 int filas = this->nfilas;
 int columnas = this->ncolumnas;
 
 Matriz res(filas, columnas);
 
 for (int i = 0; i < filas; ++i)
   for (int j = 0; j < columnas; ++j)
     res.matr[i][j] = this->matr[i][j] - b.matr[i][j];
   
 return res;
}

Matriz Matriz::operator *(const Matriz &b) const
{
 if (this->ncolumnas == b.nfilas)
 {
   int pos = this->ncolumnas;
   int filas = this->nfilas;
   int columnas = b.ncolumnas;
   
   Matriz res(filas, columnas);
   for (int i = 0; i < filas; ++i)
   {
     for (int j = 0; j < columnas; ++j)
     {
int value = 0;
for (int k = 0; k < pos; ++k) value += this->matr[i][k] * b.matr[k][j];
res.matr[i][j] = value;
     }
   };
   return res;
 }
}

bool Matriz::operator ==(const Matriz &mat) const
{
 for (int i = 0; i < nfilas; ++i)
   for (int j = 0; j < ncolumnas; ++j)
     if (this->matr[i][j] != mat.matr[i][j]) return false;
 
 return true;
}

bool Matriz::operator !=(const Matriz &mat) const
{
 for (int i = 0; i < nfilas; ++i)
   for (int j = 0; j < ncolumnas; ++j)
     if (this->matr[i][j] != mat.matr[i][j]) return true;
 
 return false;
}


Cualquier nueva duda que tenga la haré desde este mismo tema (modificando el título) para no crear nuevos temas innecesarios y no se repita la información.
Si veis algún cambio raro en el código que no haya comentado y que no se entienda comentarlo y os lo explicaré encantado.

Saludos y muchas gracias amchacon.
#89
Cita de: amchacon en 14 Diciembre 2013, 20:13 PM
No, estoy retornando una referencia. En este caso la referencia es this, asi que estoy retornando una referencia al propio objeto.

Eso te permite poner varios = consecutivos, cada uno coge la referencia del anterior ;)

PD: Si no usas la referencia no pasa nada, no es como si estuvieses creando un objeto ni nada parecido.
¿A que te refieres? No te sigo...

Vale, creo que ya lo tengo. Por lo visto, no había entendido bien que era realmente la referencia.

Cita de: xaps en 14 Diciembre 2013, 20:01 PM
Pero cuando tu retornas Matriz&, estás retornando una dirección de memoria de una matriz que al terminar la función será eliminada si no me equivoco, además de que el objeto al que se le hace la asignación debería ser un puntero, ¿no?.
La parte de que estoy hablando de punteros olvídala, era un fallo de concepto mio.
El resto sería algo como esto:
Citar
Si una función retorna una referencia, ha de tener el mismo cuidado que si la función retornara un puntero. La referencia que se devuelva debe estar ligada a algo que no sea liberado cuando la función retorne. Si no, la referencia se referirá a un trozo de memoria sobre el que ya no tiene control.
http://arco.esi.uclm.es/~david.villa/pensar_en_C++/vol1/ch11s02.html

Por lo que entiendo que en la sobrecarga del operador = sí que se pueda retornar una referencia, ya que trabaja sobre uno de sus parámetros (el implícito). Pero no entiendo porqué debería hacerlo con las sobrecargas de los operadores + - y *, ya que la matriz resultado es una matriz generada dentro de la función, por lo que a la que salga de la función ésta será eliminada y cualquier referencia a ella contendrá datos basura, ¿no?. No se si me explico bien... :S

Gracias por estar resolviéndome estas dudas ^^
#90
Cita de: amchacon en 14 Diciembre 2013, 17:33 PM
A ver, tu tenías definido el operador = para que devolviese un nuevo objeto matriz.

Como has hecho return *this esa matriz era una copia de this. Para hacer copias de un objeto se llama al constructor copia.

Si no has definido el constructor copia, el compilador crea uno por ti. El problema esque el compilador hace la copia literal. Lo que implica que se copian los punteros de la matriz tal cual.

Cuando esa matriz "copia" desaparece, se llama al destructor y se libera la memoria. Cuando la matriz "original" desaparece, se vuelve a llamar al destructor y se libera la misma memoria (¡Los punteros son iguales!). De ahí la excepción en tiempo de ejcución.

Aunque el error se solucionaría poniendo Matriz& en el retorno del operador =, no puedes dejarlo así porque ya sabes que las copias te van a fallar. Asi que te he rehecho el constructor copia (y para no copy&pastear el código, me he aprovechado del operador de asignación que hemos definido).

PD: Ya que estoy, los demás operadores (+ - *) también debería devolver Matriz& en vez de Matriz. De lo contrario estarás haciendo copias al montón :silbar:

Vale, el porqué del constructor copia lo he entendido. Pero cuando tu retornas Matriz&, estás retornando una dirección de memoria de una matriz que al terminar la función será eliminada si no me equivoco, además de que el objeto al que se le hace la asignación debería ser un puntero, ¿no?. En cambio, si retornas una copia, asignas la copia a la matriz correspondiente y luego la copia se elimina, ¿cierto?