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

#801
Podrías optar por un algoritmo que vaya calculando la raiz cuadrada por aproximación y mediante un mecanismo de prueba y error.

1. Empiezas por un número... por ejemplo el 1
2. Ahora asignas un incremento... por ejemplo una unidad.
3. Coges el número y lo elevas al cuadrado
4. Si la potencia es menor que el área:
 4.1. incrementamos el número el valor de la variable "incremento"
 4.2. volvemos al paso 3
5. Si la potencia es mayor:
 5.1. restamos al número el valor de la variable "incremento"
 5.2. dividimos el incremento entre 10
 5.3. Si el incremento es menor a, por ejemplo 0.0001 damos por bueno el resultado y salimos
 5.4. sumamos al numero el valor de la variable "incremento"
 5.5. volvemos al paso 3.
6. Si la potencia es igual:
 6.1 Damos por bueno el resultado y salimos.

Lo de poner un tope de 0.0001 al incremento es por cuestiones de precisión.

Si PI lo has definido con 4 decimales, cualquier aproximación del radio que emplee más de 4 decimales va a estar mal.

También puedes optar por algoritmos más sofisticados y potentes... pero esos no se si los vas a entender y no creo que sean el objetivo de tu práctica.

PD.: No he puesto código porque espero que al menos te curres la tarea de codificar las instrucciones.
#802
Hay que aprender a leer la documentación de las APIs antes de usarlas.

https://dev.mysql.com/doc/refman/5.0/es/mysql-query.html

"mysql_query" ejecuta una sentencia SQL (que se pasa como argumento en formato texto) y te devuelve un identificador que, mediante otras funciones, te permite acceder al resultado de la consulta.

En lo que a ti te concierne, "mysql_query" requiere como argumento una cadena de texto que contiene la consulta a ejecutar. Lo que tienes que hacer es tratar esa cadena de texto para modificar el "%g" por el valor almacenado en "nota". Una opción puede ser utilizar la función "sprintf" y después pasarle el resultado a "mysql_query".

Aunque espero que no haga falta decirlo... en tu código, la variable "nota" no tiene un valor definido.
#803
Cita de: nolasco281 en  5 Febrero 2014, 18:00 PM
1. Pero para ir guardando los registros del cada camion. estaria bien asi ya que todavía no lo estoy mostrando solo guardanlos.


Código (cpp) [Seleccionar]
Camion[nCamiones++] = nuevoCamion; //Tambien esta donde le mando los argumentos a los metodos para que se observe mejor.

Si tú en tu código tienes algo tal que:

Código (cpp) [Seleccionar]
class Camion ...

Ni puedes ni debes usar la palabra Camion para identificar un array, vector o arreglo de camiones.

Que haya nombres que colisionen ( es decir, que sean iguales ) y sirvan para cosas diferentes causa confusión a la hora de revisar el código y de encontrar errores.

Además, lo de nCamiones++... eso solo es necesario si usas arreglos al estilo de C, con contenedores no suele ser necesaria esa variable.

Cita de: nolasco281 en  5 Febrero 2014, 18:00 PM
2. Una anotación que me llamo mucho la atención es de la clase persona. Eso me hace pensar, no sé si estoy en lo correcto que debería de crear la de encabezado que gestiona los datos de una persona. y la de implementación que se encarga de comunicarse con el usuario. .

En mi caso sería una para que me gestione los datos de listaDeCamiones la .h y la otra que se comunique con el usuario .cpp

A lo que me refería con el ejemplo de la clase Persona es que hay que separar actividades que no tienen nada que ver entre sí; me explico:

Tu diseñas una clase, por ejemplo una llamada "Camion"... y le pones un método para crear instancias de esta clase que le pide al usuario vía consola los datos requeridos para su creación. Pasa el tiempo y te llega un encargo para que ahora pueda funcionar con una interfaz de ventanas... ¿que haces en este caso? Al final te toca modificar una clase que ya funciona debido a un mal diseño.

Código (cpp) [Seleccionar]

// Diseño malo

class Camion
{
  public:
    Camion( );
    Camion( const Camion& );
    virtual ~Camion( );
   
    void SetId( int id );
    void SetMatricula( const std::string& matricula );

    int GetId( ) const;
    std::string GetMatricula( ) const;

   void PideDatos( ); // funcion conflictiva
};


En cambio imagínate que en vez de optar por ese diseño "rápido" y problemático, sacas de "Camion" la función que pide los datos al usuario y la dejas en una clase independiente... en este caso para cambiar la interfaz con el usuario no hace falta tocar para nada una clase que funciona como es el caso de Camion. Y no solo eso, si además has diseñado la clase con cierto cuidado puedes hasta hacer uso de polimorfismo para que tu código pueda funcionar con varias interfaces diferentes sin tener siquiera que recompilar.

Código (cpp) [Seleccionar]

// Diseño bueno

class Camion
{
  public:
    Camion( );
    Camion( const Camion& );
    virtual ~Camion( );
   
    void SetId( int id );
    void SetMatricula( const std::string& matricula );

    int GetId( ) const;
    std::string GetMatricula( ) const;
};

class Interfaz
{
  public:
    // Funcion virtual pura, esta clase sirve para poder hacer polimorfismo
    virtual Camion* PideDatos( ) = 0;
};

class InterfazDOS
  : public Interfaz
{
  public:
    // Este metodo contiene la logica necesaria para comunicarse con el usuario via consola
    virtual Camion* PideDatos( ) override;
};

class InterfazWindows
  : public Interfaz
{
  public:
    // Este metodo contiene la logica necesaria para comunicarse con el usuario via windows
    virtual Camion* PideDatos( ) override;
};

Interfaz ObtenerInterfazUsuario( )
{
  // Estas directivas de precompilador se pueden cambiar por variables o lo que sea
  // a gusto del consumidor
  #ifdef _WIN32
    return new InterfazWindows( );
  #else
    return new InterfazDOS( );
  #endif
}

void main( )
{
  Interfaz* interfaz = ObtenerInterfazUsuario( );

  // Le pedimos al usuario los datos del camion y nos da igual si
  // lo hace a traves de una ventana de Windows o de una consola.
  Camion* camion = interfaz->PideDatos( );
}


Espero que con el ejemplo haya quedado este tema un poco más claro.

Un saludo.
#804
Cita de: dato000 en  5 Febrero 2014, 17:31 PM
WAT???? no, no no, eso no trabaja así, SDL es multiplataforma, quien realiza el trabajo de construcción grafica es el compilador, no la API como mencionas, así es como funciona su portabilidad.

WinAPI puede ser considerada como otra libreria totalmente independiente de desarrollo para graficos, pero solo funciona para windows, como conio.h, pero no puede ser comparada en lo más remoto a SDL.

Es multiplataforma si.... pero ya te digo yo que la librería compilada en linux no funciona en windows y viceversa.... motivo??

lo que he comentado, que al final se acaba apoyando de una forma o de otra en APIs específicas del sistema operativo.

Que es multiplataforma quiere decir que si con el código X generas una escena con SDL, dicho código te va a servir para compilar un programa tanto en Windows como en Linux que van a funcionar exactamente igual, sin tocar nada de código. Es como Qt... es multiplataforma... ahora si te adentras en sus entrañas descubres que tiene multitud de ifdef para separar las llamadas a la API de windows de las propias para Linux...

Si es que es muy sencillo... SDL permite crear ventanas... pero en Windows, la única entidad que proporciona acceso a esa capa es la API de Windows... o pasas por ahí o pasas por ahí, no tienes elección... otra cosa es que te programes una capa que se ponga encima y te permita abstraerte de la programación directa de la API, que dicho sea de paso es un coñazo.
#805
Cita de: dato000 en  5 Febrero 2014, 13:49 PM
demuestralo

Es fácil, las librerías SDL, por ejemplo, tienen una versión para linux, otra para windows, otra para mac... por que?? si la máquina sobre la que corre el código puede hasta ser la misma...

básicamente porque al final acaba llamando a funciones o servicios propios del sistema operativo.

En Windows este catálogo de servicios esta ubicado en la api Win32.

Por ejemplo, si tu con SDL creas una ventana... por dónde pasa eso?? el gestor de ventanas forma parte de la api de windows y todos, absolutamente todos los controles gráficos que aparecen en una ventana de windows tienen que pasar por esa api para funcionar. Al final la SDL acabará, tarde o temprano, llamando a la función CreateWindowEx de WinApi.

Es esa api la que proporciona el control de eventos, por ejemplo.
#806
Veo que te bailan un poco los conceptos. vamos por partes.

1. Constructores (parte1)

Al igual que los seres vivos ( con perdón de las reencarnaciones ) solo nacen una vez y en ese proceso ya nacen con todo, los objetos sólo se pueden crear una vez.

Cada vez que tu llamas a un constructor estás creando un objeto nuevo y diferente de los ya existentes.

El siguiente código crea tres camiones diferentes:

Código (cpp) [Seleccionar]

//Instancia de camion y separado por cada constructo     
            Camion *nuevoCamion1 = new Camion(idCam, cilindrajeCam, nPuertasCam, anioCam);
            Camion *nuevoCamion2 = new Camion(precioCam);
            Camion *nuevoCamion3 = new Camion(marcaCam, modeloCam, colorCam);


Imagino que tú ahí estás intentando asignar todas las propiedades al mismo elemento... eso se hace con los getters y los setters que has implementado.

Código (cpp) [Seleccionar]

Camion* nuevoCamion = new Camion( );
nuevoCamion->setId( idCam );
nuevoCamion->setCilindraje( cilindrajeCam );
nuevoCamion->setNPuertas( nPuertasCam );
// ...


Fíjate de paso que no he dicho "setIdCamion" ni "setCilindrajeCamion"... si la clase se llama camión es redundante y totalmente innecesario que pongas el sufijo "Camion" a todos los miembros de la clase... pero eso lo tratamos más adelante para no desviarnos.

El caso es que quizás es una buena práctica que el constructor de una clase reciba únicamente aquella información que es necesaria desde un primer momento para el buen funcionamiento del código. En tu caso, la clase Camion puede funcionar perfectamente si todos sus elementos tienen valores por defecto, luego con gestionar el constructor por defecto te sobra y te basta.

No tengas miedo a que esta forma de pensar te obligue a tener 10 líneas más de código... créeme si te digo que hay malas prácticas que generan muchas más líneas de código que además suele ser bastante ilegible.

Además, no he podido evitar fijarme en la siguiente línea:

Código (cpp) [Seleccionar]

temporalListaDeCamiones[temporalCantidadDeCamiones] = new Camion(listaDeCamiones[i]->getIdCamion(),
                                                                                  listaDeCamiones[i]->getCilindrajeCamion(),
                                                                                  listaDeCamiones[i]->getnPuertasCamion(),
                                                                                  listaDeCamiones[i]->getanioCamion(),
                                                                                  listaDeCamiones[i]->getPrecioCamion(),
                                                                                  listaDeCamiones[i]->getMarcaCamion(),
                                                                                  listaDeCamiones[i]->getModeloCamion(),
                                                                                  listaDeCamiones[i]->getColorCamion());


Resulta que tú aquí estás intentando hacer una copia de un objeto ya existente. Los chicos que diseñaron C++ eran bastante listos y ya pensaron en esta posibilidad y la incorporaron al lenguaje... estamos hablando del constructor copia.

El constructor copia se implementa por defecto en tooooodas las clases de C++... esto quiere decir que mientras la clase en cuestión no utilice memoria dinámica en sus miembros el constructor que se genera por defecto es perfectamente válido... aunque eso no quita que te apetezca implementarlo tu explícitamente para aprender, por optimización, por seguridad o por lo que sea.

El constructor copia, si lo defines explícitamente, debería tener la siguiente firma.

Código (cpp) [Seleccionar]

class Camion
{
  public:
    Camion( const Camion& );
};


Y en su implementación deberías realizar la tarea de copiar los datos de un objeto en otro:

Código (cpp) [Seleccionar]

Camion::Camion( const Camion& otro )
{
  idCamion = otro.idCamion;
  cilindrajeCamion = otro.cilindrajeCamion;
  // ...
}


Con esto, tu línea puede quedar reducida a algo tan simple como:

Código (cpp) [Seleccionar]
temporalListaDeCamiones[temporalCantidadDeCamiones] = new Camion( *listaDeCamiones[i] );

o incluso, si temporalListaDeCamiones fuese un vector, el código quedaría aún más simple:

Código (cpp) [Seleccionar]
temporalListaDeCamiones.push_back( new Camion( *listaDeCamiones[ i ] );

Resumiendo, tu clase debería tener el constructor por defecto y, si te apetece implementarlo explícitamente, el constructor copia... el resto de constructores puedes obviarlos:

Código (cpp) [Seleccionar]

class Camion
{
  public:
    Camion( );
    Camion( const Camion& otro );
};


2. Constructores (parte 2)

Cuando tú reservas memoria con un new, la memoria que el sistema te da viene "tal cual", es decir, no hay un proceso de limpieza que deje la memoria lista como si fuese a estrenar. Mas bien te encuentras con que la memoria que te ha dado el sistema tiene basura no es sino la información que otra aplicación, en su momento, escribió en esa posición y ahora ya no la usa.

Es tarea del que programa una clase inicializar toda la memoria utilizada por dicha clase. Esto quiere decir, en otras palabras, que has de dar valores por defectos a todas las variables miembros, al menos a aquellas que no sean clases.

El sitio adecuado para hacer esta tarea es en el constructor ( o constructores ). Recuerda que la llamada a un constructor cualquiera, por ejemplo al constructor copia, no implica una llamada al constructor por defecto.

Código (cpp) [Seleccionar]

Camion::Camion( )
{
  idCamion = 0;
  cilindrajeCamion = 0;
  // ...
}


Con este trabajo te aseguras que todos los objetos que se creen van a tener valores válidos SIEMPRE, que es el objetivo a conseguir. Un objeto con valores no válidos se vuelve inestable y da problemas, quedas avisado.

3. Clases (parte3)

En este apartado me voy a centrar en la nomenclatura utilizada para los miembros de la clase.

Si bien es algo meramente estético no deja de ser importante para facilitar la lectura del código.

Como te comenté anteriormente no tiene sentido que un método de la clase Camion contenga el sufijo Camion. Si por ejemplo tu dices:

Código (cpp) [Seleccionar]
camion->setNPuertas( X );

Se presupone que lo que vas a indicar es el número de puertas del camión... luego el sufijo "Camion" sobra.

Con esta premisa, los setters deberían tener más o menos esta forma:

Código (cpp) [Seleccionar]

class Camion
{
  public:
      void setId(int);         //Devuelve el Id del Camion.
      void setCilindraje(int); //Devuelve el cilindrage del camion
      void setNPuertas(int);   //Devuelve el numero de puertas del camion
      void setanio(int);       //Devuelve el año del camion
      void setPrecio(double);  //Devuelve el precio del camion
      void setMarca(string);   //Devuelve la marca del camion
      void setModelo(string);  //Devuelve el modelo del camion
      void setColor(string);   //Devuelve el color del camion
};


Aunque se les podría dar una vuelta de tuerca más.

Si has leído todo hasta aquí ya te habrás enterado de que existe el constructor copia. En tu código actual, cuando tu haces:

Código (cpp) [Seleccionar]
camion->setMarca( loquesea );

estás creando una copia de loquesea y esa copia será la que se use dentro de la función... esto supone una carga adicional y absurda, pues se crea un objeto copia con cada llamada.

Es una buena costumbre que las clases se pasen como referencias constantes. De esta forma evitas tener que crear un objeto temporal perfectamente evitable.

El cambio es relativamente sencillo:

Código (cpp) [Seleccionar]

class Camion
{
  public:
      void setId(int);         //Devuelve el Id del Camion.
      void setCilindraje(int); //Devuelve el cilindrage del camion
      void setNPuertas(int);   //Devuelve el numero de puertas del camion
      void setanio(int);       //Devuelve el año del camion
      void setPrecio(double);  //Devuelve el precio del camion
      void setMarca( const string& );   //Devuelve la marca del camion
      void setModelo( const string& );  //Devuelve el modelo del camion
      void setColor( const string& );   //Devuelve el color del camion
};


Y además tiene la ventaja de que las llamadas a las funciones son exactamente iguales que antes!!!

Ponerle la etiqueta const indica que el objeto que se pasa como argumento no va a ser modificado... una referencia es similar a un puntero y aquí tienes un ejemplo:

Código (cpp) [Seleccionar]

void func( int& numero )
{
  numero = 10;
}

void main( )
{
  int num = 0;

  std::cout << num << std::endl;
  func( num );
  std::cout << num << std::endl;
}


El resultado de ejecutar este programa es el siguiente:


0
10


4. Principio de responsabilidad única

Cada clase y cada método que programes debería regirse por este principio, por tu bien.

El principio se basa en que cada función debería dedicarse a una única tarea. Una clase que permite imprimir por pantalla no debería controlar el estado de la tarjeta de sonido, por ejemplo.

En tu caso, la clase Camion tiene dos tareas diferentes:

* Gestiona los datos de un camion
* Gestiona una lista de camiones

Esta parte de tu código en la clase Camion

Código (cpp) [Seleccionar]

  private:
      Camion**listaDeCamiones;
      int cantidadDeCamiones;


Debes eliminarla. Si quieres gestionar una lista de camiones, estupendo... pero que no sea la clase Camion la encargada de dicha gestión. Si es necesario que de dicha gestión se encargue una clase, creas una clase nueva.

Otra forma de violar este principio lo encontramos en este otro ejemplo que te vas a encontrar más veces de las que piensas:

Código (cpp) [Seleccionar]

class Persona
{
  public:
    void SetDatos( )
    {
      std::cout << "Introduce el nombre: ";
      std::cin >> nombre;
      std::cout << "Introduce su edad: ";
      std::cin >> edad;
    }

  private:
    std::string nombre;
    int edad;
};


En este caso, la clase Persona no solo gestiona los datos de una persona, también se encarga de comunicarse con el usuario para pedirle datos... mala solución.

Lo mismo esto te resulta familiar. Tu clase listaDeCamiones infringe este principio.

5. Contenedores

Insisto, si no es un requisito del ejercicio, usa contenedores en vez de arreglos. Salvo que quieras o tengas que practicar, no es necesario reinventar la rueda con cada programa... no es práctico.

Los contenedores te permiten almacenar listas de elementos de formas diversas: ordenados, sin ordenar, sin duplicados, con índice, ...

Además con los contenedores reduces las probabilidades de acceder a posiciones de memoria que no debes, te proporcionan información sobre el número de elementos que tienen, pueden crecer dinámicamente sin que tú tengas que preocuparte por ello...

Como norma general, todo son ventajas.

6. Otras cuestiones

Deberías leerte y reorganizar tu código. La última secuencia de código que has puesto deberían formar parte de la clase listaDeCamiones... ya que es esta clase la que gestiona la lista de camiones.

Por el momento creo que ya es bastante para asimilar, dedica el tiempo necesario a arreglar el código y no intentes ir rápido... las prisas no son buenas.
#807
Cita de: nolasco281 en  5 Febrero 2014, 11:06 AM
En Camion.cpp tengo el maximo ya lo quite ya que lo defini en la clase listasCamiones.cpp.

Código (cpp) [Seleccionar]
Maximo =100;
cantidadDeCamiones =0;


Y en Camion.h eso está bien como lo he modificado tanto que así lo tenía cuando funcionaba pero no de la forma correcta pero ahora que estoy hice clase listaCamiones no sé si sean necesarias.

Código (cpp) [Seleccionar]
private:
    Camion**listaDeCamiones;
    //int Maximo;
    int cantidadDeCamiones;


Prueba a poner la declaración completa de las clases... con lo que has puesto no me hago una idea de cómo ha quedado.

Cita de: nolasco281 en  5 Febrero 2014, 11:06 AM

Y este es el error con arreglo de punteros. Que es el que mencionaba de la forma de yoel_alejandro.

...

Y este es la forma en que me señala eferion.

...


Código (cpp) [Seleccionar]
Camion nuevoCamion = new Camion( ... );

Ese código está mal. new sirve para crear objetos dinámicos; y los objetos dinámicos tienen que gestionarse usando punteros:

Código (cpp) [Seleccionar]
Camion *nuevoCamion = new Camion( ... );

Además, estás redefiniendo la misma variable varias veces

Código (cpp) [Seleccionar]

Camion nuevoCamion = new Camion( ... );
Camion nuevoCamion = new Camion( ... );
Camion nuevoCamion = new Camion( ... );


Cada una de esas variables tiene que tener un nombre diferente, al menos si están en el mismo ámbito, lo que sucede en tu caso:

Código (cpp) [Seleccionar]

Camion *nuevoCamion1 = new Camion( ... );
Camion *nuevoCamion2 = new Camion( ... );
Camion *nuevoCamion3 = new Camion( ... );


Y tienes que aprender a leer e interpretar los mensajes de error... el último te está diciendo que la varible "nuevoCamion" no existe... si te fijas, en la línea anterior a la instancia de la clase la has llamado "cammion", no "nuevoCamion".

Nota final... ten siempre presente que en tu código ha de haber un delete por cada new que escribas... si no vas a acabar con lagunas de memoria... la memoria reservada por un new no se libera por sí misma.
#808
Código (cpp) [Seleccionar]
Camion(int =0, int=0, int=0, int=0, double = 0.0, string = "", string = "", string = "");

Esta declaración será broma, no???

No te recomiendo crear, de buenas a primeras, funciones que usen más de 4 argumentos porque es poco usable... si cometes el error de invertir dos argumentos te vas a dar de cabezazos hasta que des con el problema.

Además es altamente recomendable que en la declaración de las funciones aparezcan los nombres de los argumentos... normalmente cuando estés programando mirarás el archivo de cabecera para recordar el uso de las funciones, ya que suelen ser más sencillos de consultar... si tienen 20 argumentos y encima no están etiquetados te quedas sin esta opción.

Por otro lado, otra sugerencia, deberías eliminar el using namespace std de los archivos de cabecera. Usar espacios de nombres en los archivos de cabecera es una mala práctica porque obliga a arrastrar ese uso a todos los archivos que incluyan esa cabecera... y en algunos casos puede ser contraproducente... por ejemplo si dos funciones o clases se llaman igual y están en espacios de nombres diferentes.

Código (cpp) [Seleccionar]

namespace N1
{
  void func( );
}

namespace N2
{
  void func( );
}

using namespace N1;
using namespace N2;

void main( )
{
  // a que func estamos llamando??
  func( );
}


Más cosillas, si estás usando C++... por qué no usas los contenedores para almacenar la lista de camiones?? Son más potentes, versátiles y seguros que los arreglos.

* Potentes porque ofrecen una interfaz... los arreglos no.

* Versátiles porque se adaptan perfectamente a las necesidades de cada programa, solo hay que elegir correctamente el contenedor a utilizar.

* Seguros porque previenen desbordamientos y otros fallos típicos del uso de memoria dinámica.

Y además son muy sencillos de usar:

Código (cpp) [Seleccionar]

std::vector< Camion* > Camiones;
Camiones.push_back( new_camion );

Camion* camion = Camiones[ 0 ];


Cita de: nolasco281 en  5 Febrero 2014, 07:44 AM
no se, si se le olvido a yoel_alejandro asignar el apuntador hice esto.
pero el arreglo a la hora ingresar un registro del camion entra de un solo al else y me dice que ya no hay espacio para mas camiones  :-(

Código (cpp) [Seleccionar]
Camion *nuevoCamion = new Camion(idCam, cilindrajeCam,   
                             nPuertasCam,  anioCam, 
                             precioCam, marcaCam,
                             modeloCam, colorCam);
                                             
Camiones[nCamiones++] = *nuevoCamion;


Si "Camiones" es un arreglo de punteros... "*nuevoCamion" debería ser "nuevoCamion", ya que con el asterisco pasas a usar una variable estática, no un puntero.

Además no has inicializado la variable nCamiones... por lo que ésta pasa a tener un valor aleatorio y, tirando un poco de estadística... si un int ocupa 32 bits y lo llenamos con basura... ¿que posibilidades hay de que el número resultante esté entre cero y 100?? hago constar que con 32 bits el rango de valores va de –2.147.483.648 a 2.147.483.647.

Sin embargo, sacando a relucir el tema del contenedor, el código podría quedar tal que

Código (cpp) [Seleccionar]

std::vector< Camion* > camiones;

// ...

if ( camiones.size( ) < Maximo )
{
  // ...

  camiones.push_back( new_camion );
}
else
{
  // ...
}
#809
Cita de: xRodak en  4 Febrero 2014, 22:27 PM
Hola compañeros ! Me entró una duda sobre la definición de ciertas variables.

Supongamos tengo la siguiente enumeración:

namespace ENUM
{
    enum ID
    {
        a,
        b,
        c,
    };
}


Cuál sería una forma correcta de declarar un valor de dicha enumeración?

ENUM::ID       valor = ENUM::a;

o

unsigned int    valor = ENUM::a;

He visto ejemplo donde se utiliza la primera, pero según lo que he alcanzado a estudiar, la segunda sería más ideal.

Cómo sé cual de las dos debo utilizar dependiendo de cierto contexto?

Saludos y gracias de antemano.

Salvo que se indique otra cosa, los enumerados son por defecto ints.

En realidad el compilador va a convertir tus enums en ints... pero con algunas restricciones relativas al uso de operadores:

Código (cpp) [Seleccionar]

// esta linea provoca un warning
ENUM::ID valor = ENUM::a | ENUM::b;

// mientras que esta otra linea no
int valor = ENUM::a | ENUM::b;


La ventaja de usar ENUM::ID en vez de int es que el que vaya a usar tus funciones / clases sabrá en todo momento cual es el rango válido de valores... ya que vienen definidos por el enumerado.

A partir de la versión 11 de C++ se puede especificar un tipo concreto para el enum:

Código (cpp) [Seleccionar]
enum ENUM : unsigned long { a, b, c, maximo = 0xFFFFFFFFU }


Cita de: yoel_alejandro en  5 Febrero 2014, 00:13 AM
Ahora, si son "constantes" su valor no se puede cambiar una vez declarado. Entonces ¿cómo lo vas a cambiar? Cualquier instrucción de asignación de un valor luego de la declaración de la enumeración sería ilegal. Yo creo que no puedes. De hecho, estuve probándolo y el compilador me da un error en cuanto intento asignar un valor a alguna de las constantes fuera de la declaración del enum.

Estás mezclando conceptos.

Que los valores del enumerado sean constantes quiere decir que no puedes redefinir sus valores, es decir, la siguiente línea da un error de compilación:

Código (cpp) [Seleccionar]
ENUM::a = 78

Sin embargo, nada te impide almacenar el valor en una variable y manipularlo a tu antojo. La relación que se va a mantener constante durante toda la ejecución del programa es que ENUM::a siempre va a tener el mismo valor.

Cita de: yoel_alejandro en  5 Febrero 2014, 00:13 AM
Si quieres poder cambiar los valores a los campos debes usar otro tipo de dato, como un struct por ejemplo.

Sigues mezclando conceptos. Las estructuras es un tipo que permite crear estructuras ( valga la redundancia ) complejas de datos, por ejemplo te permite agrupar el puntero a un vector y la variable que indica el número de elementos en dicho vector para que siempre vayan juntos:

Código (cpp) [Seleccionar]

struct Vector
{
  int* puntero;
  int size;
};


Realmente, como he comentado antes, solo necesitas almacenar el valor del enumerado en una variable de tipo numérico ( si no es del mismo tipo que el predefinido para el enum puede que tengas que hacer un casting ) y después puedes manipular la variable a tu antojo... eso si, no hay impedimentos para que esa variable forme parte de una estructura, una clase o una unión.
#810
Cita de: yookino en  4 Febrero 2014, 17:41 PM
gracias por responder, solo que así como me dices que lo haga no le estaría asignando nada a mi arreglo, puesto que la función no retorna valores, por eso yo intento usar punteros. en cuanto al uso de getc() me pondré a leer.


Si tu estás gestionando punteros... y un vector lo es, cualquier cambio en el puntero es visible para todos los punteros que apunten a la misma posición de memoria.

cuando tú pasas como argumento de una función un vector no estás copiando literalmente ese vector, estás pasando la posición de memoria en la cual "empieza" dicho vector... o lo que es lo mismo, estás pasando un puntero.

Cualquier cambio que realices en la memoria apuntada por ese puntero se verá reflejado en el vector, ya que ambos elementos están trabajando sobre la misma posición de memoria.