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 - eferion

#811
En cualquier caso, también recordar al personal lo peligroso que es pasar como argumento una matriz o vector y no indicar como parámetros el tamaño de la misma... lo que hoy es un vector de 2 elementos mañana puede ser de N.
#812
Para que te funcione el invento, necesitas usar funciones de hora que te den una precisión de milisegundos ( y esto ya depende del sistema operativo que uses ).

La metodología básica consiste en los siguientes pasos:

1. Con el primer click, inicializas un contador a uno y memorizas la hora del evento.

2. Para cada click que se produzca después, comparas la hora actual con la de inicio del evento... si la diferencia es menor a un límite máximo definido por ti ,incrementas el contador, en caso contrario el click se considera como el primero ( paso 1 )

3. Si el contador alcanza un tope, lanzas la opción oportuna.

4. Adicionalmente podrías comprobar también que el ratón se encuentra en las mismas coordenadas todo el rato o si se han pulsado otras teclas durante el evento.
#813
lo que no termino de entender es qué tiene que ver DELPHI con C o C++
#814
Programación C/C++ / Re: El Hobbit
3 Febrero 2014, 15:41 PM
Yo tengo por aquí un código con 13 millones de líneas de código (no es coña) que tiene algunos errores (tampoco es coña), si te parece bien lo pongo por aquí a ver si alguien puede ayudarme a resolverlos...

seamos un poco serios.

Si quieres que te ayudemos, al menos podías currártelo un poco, no se:
* da alguna seña sobre qué error se produce, en qué momento, bajo qué circunstancias, si el error se produce siempre...
* recorta el código para tener una unidad mínima donde se reproduzca el error
* indica cómo es el comportamiento esperado del código.

Y si ya añades la pijotada de poner el código con colores ya ni te cuento.

En cualquier caso esta no es una asesoría donde se vayan a resolver los problemas "mas obvios", sino que la idea es intentar dar algo de soporte y ayuda de cara a que puedas ser tu capaz de resolver el problema por ti mismo.

Precisamente debido a esto último es bastante importante que aprendas a depurar tu código. Si en el futuro pretendes dedicarte a este negocio te va a tocar depurar muuuucho código que en la mayoría de los casos no solo no lo has programado tu, sino que además el que lo hizo tenía una mente oscura y perversa o, directamente, poca idea de lo que hacía.
#815
Lo primero, etiqueta el código con las etiquetas GeSHi para que sea legible... o encierra el código entre las etiquetas [code = cpp] y [/ code] (sin espacios).

En segundo lugar... ahí solo se ve cómo se imprime la lista... entonces estás asumiendo que tu lista esta bien creada?? me parece una apuesta un tanto arriesgada.

Tercero, this->nodoActual qué sentido tiene?? su uso es totalmente local, al menos en esta función, por lo que no debería ser una variable miembro.

Cuarto, entiendo que estás intentando usar una especie de algoritmo de burbuja para ordenar los resultados... lo que pasa es que tú no pretendes ordenar la lista, solo los resultados.

fíjate en las siguientes líneas de tu código:

Código (cpp) [Seleccionar]

for( ..; .. ;this->nodoActual=this->nodoActual->getSigNodo() ){
    // ...
    this->nodoActual=aux;
    // ...
    }
  }
}



Ahí te estás saltando los primeros nodos hasta llegar al mayor de ellos.

Deberías plantearte el crear una lista de resultados y ordenar dichos resultados con este algoritmo en vez de intentar ordenar sobre la marcha.
#816
Cita de: nolasco281 en  3 Febrero 2014, 01:13 AM
Hola el problema no es la herencia sino las funciones que se declaran y heredan. Si haces un código más legible y como te comente antes y pones comentarios que especifiquen que hace cada método o función sería mejor para la gente y te ayudarían mas. Saludos.

Deberías hacer caso a este comentario, ya que la gente te ayuda de forma desinteresada no está de más facilitarles un poco la vida.

Voy a partir de la base de que has eliminado cualquier característica del código que no sea compatible con el habla inglesa ( 'ñ' por ejemplo ) y de que has hecho caso a los anteriores comentarios.

Clase básica de herencia (pero básica básica )

Lo primero de todo, para que una clase "herede" de otra es imprescindible que se refleje dicha relación en la declaración de la clase hija.

En el siguiente ejemplo, sacado de tu código, se puede ver una herencia mal hecha, bueno más bien es una falta de herencia:
Código (cpp) [Seleccionar]

class Moto{
  // ...
}


Según esto Moto es una clase independiente sin parentesco con el resto de clases de tu código. Sin embargo este problema tiene una sencilla aunque rebuscada solución ( nótese la ironía ):

Código (cpp) [Seleccionar]

class Moto: public Vehiculo {
  // ...
}


Ahora "Moto" hereda de "Vehículo"... y no solo eso, además la interfaz pública de "Vehículo" es también pública en "Moto"... maravillas de la ciencia.

Eso sí, si pruebas a compilar el código con este cambio verás que sigue fallando... es un error muy común, y precisamente por ello debes estar muy atento, olvidarse de terminar la declaración de una clase con un punto y coma... esto es:

Código (cpp) [Seleccionar]

class Moto: public Vehiculo {
  // ...
};


Ahora aplicas los mismos conocimientos a la clase "Coche" y tendrás los problemas relativos a herencia terminados.

Eso sí, el código seguirá sin funcionar... por que?? muy sencillo, para que una clase hija pueda "sustituir" una función de la clase padre, es imprescindible que se cumplan dos requisitos:


  • La firma de las funciones ha de ser la misma... es decir se tienen que llamar igual, retornar el mismo tipo de dato y tener la misma cantidad de argumentos, estando estos argumentos en el mismo orden.
  • El padre ha de tener etiquetada la función como virtual.

Si examinas la lista observarás que no cumples el segundo punto. Esto da como resultado que la función no se sustituya, sino que se oculte. Esto último provoca resultados inesperados y erróneos, por lo que conviene evitarlo.

Código (cpp) [Seleccionar]

class Vehiculo{
  // ...
  public:

    // ...

    virtual void Imprimir( );
    virtual void Settipo(char*);
    virtual char* Gettipo( );

    // ...
};


Si además, resulta que estas funciones han de ser, obligatoriamente, implementadas en las clases hijas, puedes convertir las funciones en virtuales puras de una forma muy sencilla:

Código (cpp) [Seleccionar]

class Vehiculo{
  // ...
  public:

    // ...

    virtual void Imprimir( ) = 0;
    virtual void Settipo(char*) = 0;
    virtual char* Gettipo( ) = 0;

    // ...
};


De esta forma, evitas, por un lado, tener que implementar las funciones en la clase "Vehiculo" y, por otro, obligas a tener que implementar las funciones en las clases que hereden de "Vehiculo".

Y con esto acaba la lección rápida sobre herencia. Espero que haya sido de vuestro agrado :).

Otras consideraciones

En estas cosas ya me meto menos porque ya dependen de factores como exigencias del guión ( requisitos, manias de los profesores, etc )... pero aún así me veo en la obligación de comentarlo:

* Deberías usar std::string en vez de char*... mi máxima es que si se usa C++ hay que usarlo con todas las consecuencias para aprovechar al máximo sus posibilidades y para conseguir la mejor base posible.

* Usa protección para evitar referencias múltiples.

Código (cpp) [Seleccionar]

#ifndef __VEHICULO__
#define __VEHICULO__

class Vehiculo
{
  // ...
};

#endif // __VEHICULO__


Código (cpp) [Seleccionar]

#pragma once

class Vehiculo
{
  // ...
};


Cualquiera de estos dos mecanismos evita que el mismo archivo de cabecera pueda ser cargado dos veces al compilar un archivo... este efecto se produce porque los includes son expandidos al compilar, si tu tienes en el main un include a "Coche" y a "Moto" y cada uno de estos tiene un include a "Vehiculo"... entonces "Vehiculo" aparecerá dos veces en main... y eso tirará un error.

* Usa el modificador const en aquellas funciones que no modifican el estado de la clase... esto mejora la legibilidad y usabilidad del código... además te ayudará a protegerte ante modificaciones que se produzcan "sin querer" o por un despiste.

* C++11 incluye el modificador override. Este modificador se puede poner en la declaración de las funciones virtuales de las clases hijas... lo que hace este modificador es asegurarse de que la función realmente es capaz de sustituir a la del padre... en caso contrario aparecerá un error de compilación:

Código (cpp) [Seleccionar]

class A
{
  public:
    virtual void func( );

    void func2( );
}

class B : public A
{
  public:
    void func( ) override;
    void func2( ) override;
};

class C : public A
{
  public
    virtual void fnuc( ) override;
};


En este ejemplo, se producirá un error al compilar la clase A, ya que la función "func2" no es virtual. También se producirá un error en C, ya que fnuc no forma parte de A.

Como ves todo son ventajas.

* Dentro de una clase, no es necesario usar "this->" para acceder a sus variables y funciones... el uso de "this" solo es necesario en un par de ocasiones contadas, en el resto de ocasiones lo puedes obviar... el código resultante será más legible.

Y bueno, por el momento creo que ya es suficiente chicha para hoy. Espero que mis comentarios te sean de utilidad.

Un saludo.
#817
Cita de: x64Core en 31 Enero 2014, 08:57 AM
se puede hacer un casting superior a 4 bytes usando uint64_t/__int64 o incluso más si habilita extensiones especiales tales como SSE2 luego el compilador es el que se preocupa de generar las instrucciones correctas para trasladar los bytes.


Eso lo se, pero lo que intentaba dejar claro es que un int como tal son 32 bits... por lo que una conversión a int que abarque más de 32 bits forzosamente va a generar un número incorrecto...
#818
Tienes que ser consciente que, hablando de forma básica, hay dos tipos de arquitecturas "big endian" y "little endian". La diferencia básica se encuentra en la forma en la que se almacena la información en memoria.

Big endian almacena los bytes de forma "natural", es decir, el dato 0x01020304 se almacenará en memoria tal que 0x01 0x02 0x03 0x04, mientras que en un little endian quedaría almacenado tal que 0x04 0x03 0x02 0x01.

Te lo comento porque dependiendo de la forma en la que recodifiques esos datos puedes acabar obteniendo un resultado inesperado en determinadas máquinas.

Dicho esto, una forma de operar es crearte un buffer del mismo tamaño al original y usarlo para invertir los valores del buffer ( el primero al último y así ).

Tienes que tener en cuenta que si el buffer es superior a 4 bytes no vas a poder realizar conversiones a int. sin perder información.
#819
Vale, no había visto lo del unique_ptr... la próxima vez la etiqueta del código déjala algo tal que [code = cpp] sin espacios... se verán mejor estas cosas.

A ver, el unique_ptr es un puntero inteligente que tiene la particularidad de que no puede ser compartido, es decir, solo puede existir una referencia al objeto apuntado por el mismo.

El siguiente programa ilustra lo que digo:

Código (cpp) [Seleccionar]


class POO
{
 public:
   POO( )
   { std::cout << "POO::POO( );" << std::endl; }

   ~POO( )
   { std::cout << "POO:~POO( );" << std::endl; }
};

void func( POO* poo )
{
 std::unique_ptr< POO > ptr( poo );
}

void main( )
{
 POO* objeto = new POO;

 func( poo );

 std::cout << "la instancia apuntada por objeto aqui ya no existe" << std::endl;
 std::cout << "la siguiente llamada provocara un error" << std::endl;
 func( poo );
}


Como se puede comprobar, la primera llamada a poo provoca la destrucción del objeto, ya que unique_ptr sale de su ámbito y, al destruirse, se provoca la eliminación del objeto apuntado por poo.

Una cosa que sí que puede hacer unique_ptr es pasar el objeto a otro unique_ptr, de tal forma que el primer unique_ptr perderá la referencia.

Obviamente, se puede tener acceso al puntero "crudo" gestionado por unique_ptr, bien con la función get( ), bien con el operador asterisco. Sin embargo recuperar y almacenar ese puntero en tu código tiene sus peligros, ya que si el puntero inteligente se destruye también desaparecerá el objeto apuntado por tu puntero crudo... lo que pasa es que tú no te vas a enterar.

Otra opción que tienes es usar shared_ptr... lo que pasa es que en este punto tienes que tener cuidado, pues si bien shared_ptr permite tener varias copias del puntero inteligente, puede provocar lagunas de memoria si dos shared_ptr acaban apuntándose mutuamente... es decir:

Si necesitas devolver "copias" de un shared_ptr, la mejor opción es usar weak_ptr, que supone una suerte de enlace "debil" al shared_ptr. Con weak_ptr puedes extender el uso del objeto gestionado por shared_ptr por todo el sistema de una forma sencilla.

weak_ptr tiene la ventaja de que permite saber si el objeto apuntado sigue existiendo o no, lo que te permite evitar accesos no autorizados a memoria.

Código (cpp) [Seleccionar]

class POO
{
 public:
   shared_ptr< POO > referencia;

   POO( )
   { std::cout << "POO::POO( );" << std::endl; }

   ~POO( )
   { std::cout << "POO:~POO( );" << std::endl; }
};

void func( )
{
 shared_ptr< POO > ptr1( new POO );
 shared_ptr< POO > ptr2( new POO );

 ptr1->referencia = ptr2;
 ptr2->referencia = ptr1;
}

void main( )
{
 func( );

 std::cout << "llegados a este punto no hay llamadas a los destructores" << std::endl;
}


Lo dicho, los punteros inteligentes son una herramienta bastante poderosa... pero hay que tener cuidado con el diseño.
#820
estás seguro de que todos los accesos a memoria son correctos??