Título: Clase pila estática Publicado por: GominaTilted en 29 Octubre 2019, 12:46 pm Buenas, necesito implementar una clase pila estática, aunque la pila ne sí no es un array, sino un puntero a un array de enteros. El problema es que no sé cómo implementar la función copiar. Tengo un constructor de copia declarado como : Pila(const Pila&), y una sobrecarga del = tal que así const Pila& operator= (const Pila&);
Entonces, la cabecera de la función copiar debería de ser void Copiar(const Pila &), pero al intentar utilizar = para asignar las posiciones de la pila que le paso por referencia a otra y así realizar la copia me dice que al ser const no lo puede modificar (obviamente, pero es que solo estoy leyendo, no he cambiado nada). Luego viene el problema de que no puedo desapilar sobre la que paso por referencia, menudo lío llevo xD: También me gustaría que alguien me explicara la recursividad con un ejemplo que no fuera el factorial xD. Tengo que implementar de manera recursiva una función que devuelva el tamaño de la pila, pero solo le paso por argumento una pila, no lo entiendo. Lo único que se me ocurre es poner en el caso base i = 0, y en el caso recursivo después de cada llamada a la función i++, pero no sé si funcionaría como en prolog. Título: Re: Clase pila estática Publicado por: K-YreX en 29 Octubre 2019, 14:52 pm El compilador no sabe si sólo estás leyendo o estás modificando algo. Las funciones miembro de la clase que sólo "leen" y no van a modificar nada es recomendable declararlas como constantes (no constante el valor de retorno, sino constante la función). Haciendo esto permites que tanto los objetos constantes como los variables llamen a esa función pero si no lo pones entonces el compilador asume que esa función modifica algo y no te deja usarla con objetos constantes.
Te pongo un pequeño ejemplo para que veas como funciona: Código Como ves en la sobrecarga del operator=, estamos pasando un objeto de tipo Persona constante y por referencia y después estamos llamando a las funciones <getNombre()> y <getEdad()>. Para poder llamar a esas funciones, éstas deben ser constantes. (Puedes probarlo y quitar los <const> de los <get> para que veas que da un error. Para el tema de la recursividad tienes que pensar en que el/los parámetros que le pases a la función tienen que cambiar en algún momento. Entonces para tu caso que quieres calcular el tamaño de la pila puedes hacer lo siguiente: 1º Pensar en el problema sin usar recursividad. Podrías hacer por ejemplo: Código: tam := 0 2º Quitar el bucle. Para ello tienes que pensar en que cada vez que llames a la función es como una iteración. Y en cada iteración lo que hacías antes era comprobar si estaba vacía y si no lo estaba, eliminabas el tope e incrementabas el tamaño en 1. Código: Funcion tamRecursivo(Pila pila):int Título: Re: Clase pila estática Publicado por: GominaTilted en 29 Octubre 2019, 17:07 pm Gracias, la recursividad ya la he entendido. El problema lo sigo teniendo con la función Copiar, ya que al ser una array la pila, he planteado lo siguiente:
- La cima de inicio está en la posición -1. - Desapilar resta 1 a la variable privada ”cima”, y apilar suma 1 y en esa posición siguiente sobreescribe el dato. Por lo tanto mi función Copiar es así: Código: void Pila::Copiar(const Pila &p) Título: Re: Clase pila estática Publicado por: K-YreX en 29 Octubre 2019, 17:41 pm Lo que tú tienes es una función miembro de una clase, por lo tanto esa función se la aplicas a una pila que ya existe, no tienes que crear una Pila dentro de la función.
La Pila p1 es local a esa función. Tú tienes que trabajar con el objeto implícito que llama a la función <Copiar()>. Además de eso si estás pasando como parámetro una Pila <p> por referencia y constante, no puedes desapilarla porque es constante. Código
EDIT: Además si lo haces de esa forma estás invirtiendo las pilas. Si tienes una pila original: p = {1,2,3,4,5} y llamas a la función copiar con otra pila p2, el resultado sería: p2 = {5,4,3,2,1} Título: Re: Clase pila estática Publicado por: GominaTilted en 29 Octubre 2019, 18:59 pm Muchas gracias. No había pensado que podía usar las funciones sobre el propio objeto, muchas horas delante de esto xD.
Título: Re: Clase pila estática Publicado por: GominaTilted en 29 Octubre 2019, 21:22 pm Vengo con la última duda, pensaba que había acabado pero no :(. He intentado hacer la sobrecarga del operador =. Tengo esto:
Código: const Pila& Pila::operator= (const Pila & p) Creo que está bien, pero al compilar la línea p = p2 (siendo p una pila llena con valores {1...4} y p2 una pila vacía), salta el error "exited, segmentation fault". Título: Re: Clase pila estática Publicado por: K-YreX en 30 Octubre 2019, 02:24 am Muchas gracias. No había pensado que podía usar las funciones sobre el propio objeto, muchas horas delante de esto xD. Esa es precisamente la utilidad de las funciones miembro de una clase: actuar sobre el objeto/instancia que las llama de forma implícita.Vengo con la última duda, pensaba que había acabado pero no :(. He intentado hacer la sobrecarga del operador =. Tengo esto: Es mejor que añadas también el código de las funciones que intervengan en todo el proceso de alguna manera u otra para saber dónde está el fallo exactamente.Código: const Pila& Pila::operator= (const Pila & p) Creo que está bien, pero al compilar la línea p = p2 (siendo p una pila llena con valores {1...4} y p2 una pila vacía), salta el error "exited, segmentation fault". Además ten cuidado con las mayúsculas. Suele ser habitual usar la nomenglatura UpperCamelCase (que como se nota en el nombre, cada palabra empieza por mayúscula, para designar clases) y la nomenglatura lowerCamelCase (todas las palabras empiezan por mayúscula menos la primera) para funciones. Esto es una convención, no son reglas estrictas pero en el caso del <return> si es necesario ya que C++ es un lenguaje sensible a mayúsculas y minúsculas (no es lo mismo escribir una palabra usando mayúsculas que minúsculas). Título: Re: Clase pila estática Publicado por: GominaTilted en 30 Octubre 2019, 10:20 am Lo del return es que lo estaba copiando a mano y me he equivocado :-X. Las funciones implicadas son:
Código: void Pila::Vaciar() Código: void Pila::Copiar(Pila p) Código: void Pila::Apilar(int n) EDIT: dejo también el constructor de la clase, constructor de copia y desrtuctor. Código: Pila::Pila() Título: Re: Clase pila estática Publicado por: K-YreX en 30 Octubre 2019, 16:47 pm Te recomiendo cuando pongas un código en el que tienes problemas que lo copies del original. No sería la primera vez que el código está mal escrito, al escribirlo aquí se escribe bien y es imposible detectar el error.
Aunque en este caso veo un par de problemas:
Título: Re: Clase pila estática Publicado por: GominaTilted en 30 Octubre 2019, 18:57 pm Gracias, ya tengo la <Cimapila()>, estaba la asignación al revés. Supongo que en <Copiar()> sí que tengo que generar un espacio nuevo en memoria, ya así te aseguras que hay un espacio reservado, aunque creo que al crear el objeto se debería de reservar ese espacio, no lo entiendo muy bien. Al hacer la sobrecarga de la asignación estamos en el mismo caso. Lo que si que tendría que hacer es un “delete [] v” en el destructor en vez de <Vaciar()>, y creo que también en la sobrecarga del operador.
Te dejo la función <Copia()>, la sobrecarga y un pantallazo con los valores que obtengo al realizar la asignación: Código: const Pila& Pila::operator= (const Pila & p) Código: void Pila::Copiar(Pila p) https://ibb.co/LzQbPKT PD: perdón no sé cómo se ponen imágenes xD. Título: Re: Clase pila estática Publicado por: K-YreX en 30 Octubre 2019, 22:52 pm Bueno, a ver. Lo primero es que en la imagen estás usando un constructor de Pila que recibe un parámetro (int) y ese constructor no sé qué hace por lo que supondré que el parámetro es el tamaño de la pila y el constructor sin parámetros pone un tamaño estándar de 3.
Los <new> y los <delete> no se usan a lo loco pensando "así me aseguro de que hay espacio reservado", no. Tienes que saber cuando hay espacio reservado y cuando no, reservar la memoria justa y necesaria y liberarla correctamente. Los constructores son las funciones que llaman los objetos cuando se crean. Estos objetos como justo se están creando no tienen nada todavía por lo que sí necesitas reservar memoria. El de por defecto está bien, el de con parámetros supondré que también pero el de copia no. Cuando creas una instancia con el constructor de copia, no le estás asignando espacio. Código
El destructor como bien dices debe liberar la memoria de esa Pila. Y es más, no necesitas <Vaciar()> la Pila; con liberar la memoria reservada sería suficiente. La función <Copiar()> no está bien. Esa función la usarás siempre sobre instancias que has creado antes por lo que ya tienen memoria reservada. La duda es: tendrá el mismo tamaño la Pila sobre la que copias que la Pila que copias? Es algo que no puedes asegurar si puedes crear Pilas de distintos tamaños por lo que lo que tendrías que hacer es liberar la memoria de la que quieres copiar y asignarle la misma longitud que a la otra nuevamente (pero sin olvidar primero liberar la memoria que ya tenía). Código
El operador = está bien ya que haces lo que te digo para la función <Copiar()> pero claro, lo de borrar la memoria que tenía y crear memoria nueva... una de dos, o lo haces dentro de la función <Copiar()> o lo haces fuera pero no lo hagas dos veces. EDIT: Si las funciones <Altura()> y <Altura2()> son para mostrar el tamaño de la Pila, no tiene sentido que las hagas externas a la clase y reciban la Pila como parámetro. Es mejor que las hagas dentro de la clase y que no crees dos funciones diferentes para lo mismo. Título: Re: Clase pila estática Publicado por: GominaTilted en 31 Octubre 2019, 12:48 pm Ahora tengo dos constructores, el por defecto y el que le paso el tamaño de la pila. Todas las cosas que no tengan sentido en cuanto al planteamiento del problema es (como Altura y Altura2), tienen que ver con el enunciado de la práctica, está hecho para que si no te va la sobrecarga no te funcionen bien las recursivas con referencias.
Entonces a lo que iba, si le paso al de copia por parámetro el tamaño máximo de la pila no va, pero si no se lo paso lo ejecuta en bucle. Mis constructores: Código: Pila::Pila() Y aquí Copiar() y la sobrecarga: Código: void Pila::Copiar(Pila p) La función Copiar() funciona bien, ya que al ponerle cout saca los valores correctos, entonces el error supongo que es del constructor de copia. Cuando no entra en bucle infinito me sale el error "double free or corruption (fasttop)", el cual he buscado en stack overflow pero no he entendido mucho, simplemente que es posible que al hacer la asignación libere el espacio de memoria de la parte derecha, no izquierda. Copia bien en la pila 2, pero la original la modifica y se queda 0 0 3 4, como si hubiese borrado las dos primeras posiciones o fueran espacios de memoria a los que no se puede acceder. Título: Re: Clase pila estática Publicado por: K-YreX en 31 Octubre 2019, 13:41 pm El constructor de copia tiene un problema y es que le asignas 10 a <max> en vez de asignarle <p.max> ya que la longitud del nuevo tiene que ser la misma que la del que copias.
Y la función <Copiar()> tiene otro problema y es que estás incrementando <cima> pero en ningún momento la pones a -1 antes de empezar a incrementar y tampoco actualizas el valor de <max>. Además como ya no estás usando las funciones <Apilar()> y <Desapilar()> en la función <Copiar()> (y por tanto ya no estás modificando la original) ahora sí puedes (y debes) pasar el parámetro constante y por referencia. Título: Re: Clase pila estática Publicado por: GominaTilted en 31 Octubre 2019, 13:54 pm El constructor de copia tiene un problema y es que le asignas 10 a <max> en vez de asignarle <p.max> ya que la longitud del nuevo tiene que ser la misma que la del que copias. No sabía si tenía que actualizar el valor de max, ya que como el array se crea en función de p.max, pero claro, no había pensado que interviene todo el objeto. El resto podría haber estado dándole vueltas 1 mes y no lo saco xD. Muchas gracias, ya va. ¿Por qué en la función copiar es conveniente pasar el objeto por referencia y ponerlo como const? Gracias de nuevo, esta es la última pregunta de verdad ^^.Y la función <Copiar()> tiene otro problema y es que estás incrementando <cima> pero en ningún momento la pones a -1 antes de empezar a incrementar y tampoco actualizas el valor de <max>. Además como ya no estás usando las funciones <Apilar()> y <Desapilar()> en la función <Copiar()> (y por tanto ya no estás modificando la original) ahora sí puedes (y debes) pasar el parámetro constante y por referencia. Título: Re: Clase pila estática Publicado por: K-YreX en 31 Octubre 2019, 14:06 pm Siempre que los objetos que se pasan como parámetro no se van a modificar es recomendable pasarlos constantes para asegurar que pase lo que pase no se va a modificar (como decirle al compilador "no me dejes modificar este objeto ni por error") y por referencia para que así se pase la dirección de memoria del objeto original y no se cree una copia local (ya que si no se pasa por referencia, se pasa por valor y entonces lo que se hace es crear una copia del objeto con su consiguiente gasto de memoria).
Título: Re: Clase pila estática Publicado por: GominaTilted en 31 Octubre 2019, 14:50 pm Siempre que los objetos que se pasan como parámetro no se van a modificar es recomendable pasarlos constantes para asegurar que pase lo que pase no se va a modificar (como decirle al compilador "no me dejes modificar este objeto ni por error") y por referencia para que así se pase la dirección de memoria del objeto original y no se cree una copia local (ya que si no se pasa por referencia, se pasa por valor y entonces lo que se hace es crear una copia del objeto con su consiguiente gasto de memoria). Muchas gracias, no lo sabía. |