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 - K-YreX

#441
Yo diría que las funciones virtuales puras lo que hacen es imponer condiciones al programador. Imagina que creas una clase <Animal> que no vas a instanciar directamente sino que la vas a usar de molde para crear otras clases hijas que hereden de <Animal>. Entonces en esta clase <Animal> deberías crear funciones virtuales puras como <comer()>, <relacionarse()>, etc. Lo que consigues al hacerlas virtuales puras es que cuando crees un tipo de animal concreto y éste herede de <Animal> te verás "obligado" a redefinir esas funciones virtuales puras.

Puedes verlo también de otra forma. Tú puedes crear una clase abstracta de la que heredarán otras clases pero resulta que las clases hijas no las vas a hacer tú, sino que lo harán diferentes programadores, pero para que todo funcione bien tú necesitas decir al resto de programadores que sus clases deben contener una serie de funciones sí o sí. Cómo lo haces? Creas esas funciones como virtuales puras en la clase abstracta.
En el mismo ejemplo de antes, tú dices a un grupo de personas que se inventen unos animales y que tengan las características que ellos quieran PERO que todos los animales deben emitir un ruido, el que sea. Pues creas una función virtual pura que sea <emitirRuido()> y cuando las demás personas hagan que sus clases hereden de <Animal> deberán hacer que cada clase implemente de alguna forma esa función <emitirRuido()>.

Esto yo por ejemplo lo vi bastante bien al aprender Java donde esto se usa en las interfaces porque Java no permite la herencia múltiple. No lo he usado más que en un par de códigos pequeños en forma de "apuntes" pero digamos que así es cómo yo lo entiendo. Puede que tenga otros usos o interpretaciones y quien las conozca puede corregirme. :-X
#442
Cita de: Loretz en  5 Octubre 2019, 04:01 AM
En un ciclo for, donde se usa para incrementar la variable de control, el compilador puede lucirse con poco, usa la versión más eficiente sin preguntar. Sin trucos ++i hace menos cosas que i++.
Con lo que está en negrita, quieres decir que tanto si se usa el postincremento como el preincremento, el compilador lo optimizará al mismo nivel? Es decir, que daría igual usar uno que otro? Lo digo porque yo era de los que empezó a programar y a hacer los for con i++ hasta que me dijeron que era mejor usar ++i, pero claro, eso me ha chocado con el tema de que el preincremento sí es mejor pero cuando se trata de objetos y no de tipos primitivos.

Cita de: RayR en  5 Octubre 2019, 05:28 AM
Porque si compilamos el código original de MAFUS con optimizaciones, como es debido, veremos que tampoco es de utilidad, ya que todos los compiladores modernos se darán cuenta de que no hace nada, así que eliminarán todas las instrucciones y simplemente harán que main retorne 0.
Cierto. Sí que se me ocurrió añadir las opciones -O1 y -O2 y se ve eso que dices. En el primer caso lo que se obtiene es esto:
Código (asm) [Seleccionar]

mov     eax, 0
ret

Y en el segundo caso lo que se obtiene es:
Código (asm) [Seleccionar]

xor     eax, eax
ret

Por lo que es cierto que el compilador ve que no se usan las variables para nada y entonces omite las sentencias.
#443
Supongo que si te han pedido un ejercicio así os habrán explicado un poco sobre programación orientada a objetos, no? Conceptos como los de clase, constructor, atributos, funciones miembro, etc.
Lo que te están pidiendo es que crees una clase llamada Tiempo con una serie de atributos privados: hora, minuto y segundo.

Si no sabes de estas cosas que te he dicho pregunta más específicamente qué es lo que no entiendes o qué dudas tienes. También puedes buscar información sobre clases para poder resolver el ejercicio.
#444
Cita de: RayR en  2 Octubre 2019, 19:33 PM
En realidad, como curiosidad, y contrario a la engañosa creencia antes mencionada, en algunos casos el postincremento/postdecremento (con tipos básicos) en teoría podría ser más eficiente que el preincremento, ya que el preincremento genera una dependencia de datos que no existe con el post, por lo que en este último caso podría haber un mejo aprovechamiento de los pipelines del procesador. Eso sí, en la práctica yo nunca lo he visto, pero he leído de dos programadores que lo afirman.
No había procesado esto bien y la verdad nunca habría pensado que eso fuera así ya que yo creía que el operador que mantiene una dependencia es el postfijo que necesita usar otro registro (como se veía en los ensambladores de MAFUS y engel lex) para almacenar el valor todavía sin incrementar. Sin embargo, me parece curioso aunque se me escape de las manos el entenderlo.

Entonces para resumir: el estándar C++17 especifica que primero se evalúa la parte de la derecha y después la de la izquierda pero los efectos colaterales siguen sin estar definidos; a diferencia de Java que evalúa de izquierda a derecha y especifica que los efectos colaterales se resuelven inmediatamente después.

Cita de: NEBIRE en  4 Octubre 2019, 09:41 AM
Cada lenguaje tiene su sintaxis y su especificación. Esperar resultados idénticos es pecar de ingenuo (precisamente porque la mayor parte de las veces así sucederá, teniendo ambos lenguajes un origen común).

Ese "Quiero terminar de entenderlo", me suena a perder el tiempo...
En vez de hacer pruebas, lo que tienes que hacer es consultar la especificación del lenguaje (de uno y otro)... para ver cuál es el orden de precedencia de la asignación. Ya está, 1 minuto de lectura, no varios días haciendo pruebas... si no, aprender se te hará eterno.
Si la especificación del lenguaje es ambigua en tal punto, entonces ten por cierto que cada compilador tiene vía libre para hacer como le dé la gana. Ahí, si procede hacer pruebas para ver como se comporta el compilador que estés usando.
Es posible que algunas personas lo vean como una pérdida de tiempo pero me interesaba saber cuáles eran las diferencias entre estos dos lenguajes en este aspecto y al final parece que lo estoy consiguiendo con las aportaciones del resto de miembros y sobre todo con las explicaciones de RayR, que agradezco.
También es verdad que consultando las especificaciones de cada lenguaje acabaría antes pero entre que no sé dónde localizarlas ni hasta donde llegaría a entender pues... supongo que dentro de mis posibilidades haré lo que pueda y en este caso lo que podía hacer eran pruebas para intentar sacar alguna conclusión de forma práctica. He visto que no llegaba a nada con pruebas pues entonces he probado en el foro.
Si todos nos tuviésemos que buscar la vida yendo a las fuentes oficiales de cada tema, no servirían de nada los foros porque lo que cualquiera pueda afirmar en un foro tendrá que estar apoyado por algún tipo de documentación oficial.
#445
Cita de: engel lex en  2 Octubre 2019, 15:47 PM
aqui hay un tema que se explicó con un poco de detalle el asunto relacionado a los incrementos/decrementos post/pre, esto es un problema comun a descubrir cuando se está aprendiendo

https://foro.elhacker.net/buscador-t483138.0.html

no es un asunto de java vs c++ es un asunto de nivel mas bajo...
Gracias por el enlace. No sabía nada de los sequence points. Lo de Java vs C++ lo decía porque aun suponiendo que cada lenguaje funciona con sus normas, pensaba que seguirían un mismo estándar de orden de procesamiento. Pero como explico más adelante parece que cada uno usa un orden diferente.

Cita de: RayR en  2 Octubre 2019, 19:33 PM
tienes garantizado que primero se evaluará lo de la derecha (previousIndex--) y obtendrás resultados consistentes. Aún así, yo recomendaría que hagas el decremento en su propia línea, tanto porque así tu programa funcionará en cualquier versión de C++, como porque es menos ambiguo para el programador; no todos están familiarizados con C++17, y aunque lo estemos, se nos pueden olvidar las reglas de evaluación.
Ya he visto que es mejor separar los incrementos/decrementos en líneas diferentes pero quiero terminar de entenderlos. He realizado otra prueba con:
Código (cpp) [Seleccionar]

int numeros[5] = {1,2,3,4,5};
int j = 2;
numeros[j+1] = -numeros[j--];

Y el resultado es: numeros = {1,2,-3, 4,5}. Por lo que saco que primero se obtiene el valor almacenado en <numeros[j]>, luego se decrementa <j> y después se calcula la posición de memoria del valor <numeros[j+1]>. Como el índice <j> se decrementa antes de calcular la posición de memoria pues la posición vuelve a ser la misma al sumarle 1 al índice. (Todo esto compilado con -std=c++17)

Sin embargo, en Java si probamos a hacer lo mismo:
Código (java) [Seleccionar]

int numeros[] = {1,2,3,4,5};
int j = 2;
numeros[j+1] = -numeros[j--];

El resultado es: numeros = {1,2,3,-3,5}. Por lo que aquí parece que antes de realizar el decremento ya tiene la posición de memoria donde lo va a guardar calculada y por eso el decremento no se junta con el +1 llegando de nuevo a la misma posición como ocurre en C++.

Estoy estudiando la precedencia de los operadores y por eso me ha sorprendido que el resultado fuera diferente teniendo en cuenta que los incrementos/decrementos tienen más preferencia que las asignaciones.
También he visto en algunos sitios que los operadores en postfijo tienen más preferencia que en prefijo... pero en otros sitios aparece como que tienen la misma prioridad. No sé si esto depende también del estándar.
Y la última pregunta es: en una sentencia con postincremento, el incremento se produce cuando ya se ha terminado de ejecutar la sentencia (línea completa) o justo después de usar el valor sin incrementar?
#446
Ya sé que este suele ser un tema básico pero me he encontrado con un resultado inesperado en el funcionamiento de estos operadores.
Mi problema es que estaba implementando un algoritmo de ordenamiento por inserción tanto en C++ como en Java; sin embargo, el resultado obtenido en C++ no era el que esperaba por eso pongo la duda en este foro.
Aquí el código en Java:
Código (java) [Seleccionar]

public static void insertionSort(int[] numbers){
   for(int i = 1; i < numbers.length; ++i){
       int currentValue = numbers[i];
       int previousIndex = i-1;
       while(previousIndex >= 0 && currentValue < numbers[previousIndex])
           numbers[previousIndex+1] = numbers[previousIndex--];
       numbers[previousIndex+1] = currentValue;
       showArray(numbers);
   }
}


Y aquí el código en C++:
Código (cpp) [Seleccionar]

void insertionSort(int *numbers, const int size){
   for(size_t i = 1; i < size; ++i){
       int currentValue = numbers[i];
       int previousIndex = i-1;
       while(previousIndex >= 0 && currentValue < numbers[previousIndex])
           numbers[previousIndex+1] = numbers[previousIndex--];
       numbers[previousIndex+1] = currentValue;
       showArray(numbers, size);
   }
}

Como se puede ver, códigos idénticos. El problema está en la línea 6 del código en C++. He visto que había valores que se repetían y después de un rato investigando he visto que si en C++ se cambia la línea 6 por:
Código (cpp) [Seleccionar]

numbers[previousIndex+2] = numbers[previousIndex--];

Entonces sí funciona. Y si se cambia el bucle <while> por:
Código (cpp) [Seleccionar]

while(previousIndex >= 0 && currentValue < numbers[previousIndex]){
   numbers[previousIndex+1] = numbers[previousIndex];
   --previousIndex;
}

También funciona correctamente. Entonces el problema sé que está en el orden en que se realiza el decremento. Me gustaría sabes cómo funciona eso en profundidad ya que veo que no funciona igual en Java que en C++.

PD: Agradecería también una explicación del funcionamiento en Java para ver cuáles son las diferencias exactamente. O si es mejor que abra otro tema en el foro de Java para esta parte me lo podéis decir también. :-X :-X
#447
Eso no funciona primero porque en la función <scanf()> estás usando %d que es para variables de tipo entero (int) y además estás intentando guardar en la posición 30 del array <frase>. Esa posición no es accesible ya que si el tamaño es 30, las posiciones van de 0 a 29.
Para guardar cadenas es mejor que uses la función <fgets()>.

#include <stdio.h>

#define MAX_SIZE 30 // constante para determinar la longitud maxima de la cadena

int main(){
    char frase[MAX_SIZE];

    printf("Introduce una frase: ");
    fgets(frase, MAX_SIZE, stdin);

    // el resto del programa

    getchar();
    return 0;
}

El resto del programa está bien pero como recomendaciones te diría que no uses la librería <conio.h> (que sirve para la función <getch()>) porque no es estándar. Usa mejor la función <getchar()> que pertenece a la librería <stdio.h> y así sólo necesitas esa librería.

Y en el <switch> puedes hacer que cuente también las mayúsculas:

for(size_t i = 0; i < MAX_SIZE; ++i){
    switch(frase[i]){
        case 'a': case 'A': ++vocal_a; break;
        case 'e': case 'E': ++vocal_e; break;
        //...
    }
}
#448
Cita de: jorgecotrinax en 30 Septiembre 2019, 16:07 PM
esto lo ise a proposito por que me daba error si lo ponia correctamente
Estudiante( char* cod, string nom,float pode ){
            cod=codigo; // esta al reves
            nom =nombre; // esta al reves
            pode = poderado; // esta al reves
            siguiente = NULL;
        }

al parecer era por la cantidad de datos que puse [5]

char codigo[5];

lo quite  [5]y me codigo se ejecuto correctamente
la pregunta como hago para yo elegir la cantidad de datos de cada archivo o debo usar
solamente uso el tipo de dato correcto al fina solo trato de hacer esto
-> https://drive.google.com/open?id=1LD0zBfxs1FsDMGSTp1th0zlob7P6HxkR
Lo siento pero sigues sin ser específico. Igual soy yo pero sigo sin entender tu duda... pusiste [5], dónde?? :huh: :huh:
Citar
como hago para yo elegir la cantidad de datos de cada archivo
Te refieres al largo de la variable <cod> y <codigo>?? Eso tienes que controlarlo con otra variable. Cuando pasas a esa función el parámetro <cod>, estás pasando la dirección de memoria en la que empieza el código <cod> pero para saber cuándo acaba o cómo de largo es, debes pasar otro parámetro que sea el largo.
Si te da igual lo largo que sea <cod> porque en <codigo> vas a copiar sus X primeros caracteres podrías hacer algo como (de paso te pongo cómo hacer estas cosas sin andar cambiando nombres usando la partícula <this>):
Código (cpp) [Seleccionar]

Estudiante(char *codigo, string nombre, float poderado){
    this->nombre = nombre; // this->nombre es el del objeto y nombre solo es el parametro
    this->poderado = poderado;
    this->siguiente = NULL; // se puede omitir pero poniendolo se ve mejor que es un atributo del objeto
    strncpy(this->codigo, codigo, X); // asi copias en this->codigo los X primeros caracteres de codigo
}

Si una vez más no he acertado con la interpretación pues bueno, una explicación que te llevas de regalo... :rolleyes: :-X
#449
Cita de: jorgecotrinax en 30 Septiembre 2019, 04:45 AM
si se eso que esta al reves es que no me lo aceptaba me parecio raro probe quitando la cantidad de datos que quiero "[4]" y me permitio hacerlo como es correctamente pero como hago cunado me piden una cantidad fija de datos ?
No sé a que te refieres con eso último. Si tienes un constructor con 3 parámetros, cuando crees un objeto, debes hacerlo con 3 parámetros. Si a lo que te refieres es a poder crear objetos pasando 3 parámetros o pasando otro número de parámetros lo que debes hacer es sobrecargar el constructor con otro número de parámetros.
Si no te refieres a eso, intenta explicármelo otra vez de otra forma para que pueda ayudarte. Podrías ponerme cómo lo tenías y qué era lo que no te dejaba o qué es lo que quieres poder hacer. :-X
#450
No tiene mucho sentido ya que la gracia de usar una Pila es insertar al principio en O(1) y eliminar del principio en O(1). Si insertas y eliminas por el final, las operaciones pasarán de ser O(1) a O(n)... pero si es lo que quieres, me limito a darte una opción.
Creas un nodo auxiliar que empezando en <cabeza> vaya avanzando hasta que <aux->siguiente> sea igual a <cola>. Entonces eliminas <cola> e igualas <cola> a <aux>. Cuidado con lo de "hasta que <aux->siguiente> sea igual a <cola>" ya que puedes tener dos elementos iguales pero que no sean el mismo. Tendrás que comprobarlo con sus direcciones de memoria.
Otra forma que se parecería un poco más a la estructura de una pila (aunque poco) es tener una función que devuelva el número de elementos de la pila. El típico <size()> del contenedor <stack> de la STL. Entonces lo mismo, avanzas con un puntero auxiliar hasta uno menos del último y haces lo mismo de antes.

PD: Tal y como quieres usarlo sería mejor usar listas doblemente enlazadas, en las que cada nodo tiene un puntero a siguiente y otro a anterior. La gracia de estas es trabajar con inserciones y borrados en ambos extremos en O(1). Así sólo tendrías que empezar en <cola>, crear un puntero auxiliar que apunte también a <cola>, hacer que <cola> apunte al anterior y borrar el auxiliar.