Foros del Web » Programación para mayores de 30 ;) » C/C++ »

Inicializar array de cadenas en constructor

Estas en el tema de Inicializar array de cadenas en constructor en el foro de C/C++ en Foros del Web. Ya solo me falta un detalle. Necesito tener un array de cadenas que sea accesible en mas de un sitio asi que lo que hago ...
  #1 (permalink)  
Antiguo 11/04/2016, 06:02
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 8 meses
Puntos: 3
Inicializar array de cadenas en constructor

Ya solo me falta un detalle. Necesito tener un array de cadenas que sea accesible en mas de un sitio asi que lo que hago es esto:
Código C++:
Ver original
  1. private:
  2.    static const AnsiString HintsMessages[18],HintsMessagesTypes[2];
Y en el constructor hago esto:
Código C++:
Ver original
  1. __fastcall TForm1::TForm1(TComponent* Owner)
  2.    : TForm(Owner)
  3. {
  4.    //Inicializo la cadena constante de validacion de entrada del teclado
  5.    GoodKey = "0123456789abcdefABCDEF";
  6.  
  7.    const AnsiString TForm1::HintsMessages[18]={"Este mensaje activa la ventana.",
  8.                     "Este mensaje pone el foco en la ventana.",
  9.                     "Este mensaje quita el foco de la ventana.",
  10.                     "Este mensaje indica si se redibuja la ventana o no.",
  11.                     "Este mensaje se envia para preguntar a una ventana si se puede cerrar al cerrar sesión.",
  12.                     "Este mensaje se envia para indicar a una ventana que se va a cerrar sesión.",
  13.                     "Este mensaje envia un clic izquierdo.",
  14.                     "Este mensaje es el que se da al pulsar el botón izquierdo del ratón.",
  15.                     "Este mensaje es el que se da al soltar el botón izquierdo del ratón.",
  16.                     "Este mensaje es el que se da al hacer doble clic con el botón izquierdo del ratón.",
  17.                     "Este mensaje es el que se da al pulsar el botón derecho del ratón.",
  18.                     "Este mensaje es el que se da al soltar el botón derecho del ratón.",
  19.                     "Este mensaje es el que se da al hacer doble clic con el botón derecho del ratón.",
  20.                     "Este mensaje es el que se da al pulsar el botón central del ratón.",
  21.                     "Este mensaje es el que se da al soltar el botón central del ratón.",
  22.                     "Este mensaje es el que se da al hacer doble clic con el botón central del ratón.",
  23.                     "Este mensaje es el que se da al girar la rueda vertical del ratón.",
  24.                     "Este mensaje es el que se da al girar la rueda horizontal del ratón."};
  25.  
  26.    const AnsiString TForm1::HintsMessagesTypes[2]={"Esta opción espera la respuesta. El valor de retorno será la respuesta obtenida.",
  27.                          "Esta opción no espera respuesta alguna. Retorna 1 si se envió correctamente y 0 si falló."};
  28. }
Lo que queria realmente es hacerlo con const char*HintsMessages[] y const char* HintsMessagesTypes[] pero creo que sería aun mas complicado.
Con lo que tengo me da estos errores:
Cita:
[C++ Error] Main.cpp(26): E2089 Identifier 'HintsMessages' cannot have a type qualifier
[C++ Error] Main.cpp(45): E2089 Identifier 'HintsMessagesTypes' cannot have a type qualifier
Es que no me hace nada de gracia hacerlo con un TStrings y tener que añadir uno a uno. Por eso quiero hacerlo con un array, para inicializarlo de golpe todo.
  #2 (permalink)  
Antiguo 11/04/2016, 06:37
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: Inicializar array de cadenas en constructor

Un miembro static no debe ser inicializado desde el constructor sino que debe tener su propia "implementación" ya que entonces se estaría incicializando cada vez que se construye un nuevo objeto.

La incialización de miembros estáticos se hace tal que:

Código C++:
Ver original
  1. class POO
  2. {
  3.   static int var;
  4. };
  5.  
  6. int POO::var = X;

Pudiendo estar la inicialización tanto en la cabecera como en el fichero de implementación.

En tu caso además los arreglos son const, luego no vas a poder modificar su valor una vez se hayan inicializado. Dado que los elemento static tienen su propia inicialización y que los has declarado const, no es posible modificar su valor en el constructor.

El siguiente código te debería funcionar:

Código C++:
Ver original
  1. const AnsiString TForm1::HintsMessages={
  2.   "Este mensaje activa la ventana.",
  3.   "Este mensaje pone el foco en la ventana.",
  4.   // ...
  5. };
  6.  
  7. __fastcall TForm1::TForm1(TComponent* Owner)
  8.    : TForm(Owner)
  9. {
  10.   //...
  11. }

También puedes plantearte usar std::array. Se comporta como un std::vector salvo en el detalle de que el tamaño es fijo, no puedes añadir nuevos elementos ni por supuesto eliminarlos... es el equivalente a lo que estás haciendo ahora mismo. Esta opción puede ser especialmente atractiva si necesitas usar iteradores.

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #3 (permalink)  
Antiguo 11/04/2016, 07:24
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 8 meses
Puntos: 3
Respuesta: Inicializar array de cadenas en constructor

A ver, lo de static lo puse porque buscando información vi un ejemplo que para inicializar un array de cadenas decía que tenia que ser asi pero realmente te lo que necesito es un array de cadenas constantes que nunca se modificarán y que sólo necesito poder leer la cadena correspondiente al índice deseado. Si declaro el array de constantes como global va perfecto, el problema está en ponerlo como privado de la clase.
  #4 (permalink)  
Antiguo 11/04/2016, 07:37
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: Inicializar array de cadenas en constructor

Con static lo que consigues es que ese array sea común para todos los objetos que crees de tipo TForm. De hecho la forma habitual de acceder a dicho array será TForm::HintsMessages en vez de this->HintsMessages.

Si no tienes ese requisito y únicamente buscas que sean constantes puedes eliminar static sin problemas e inicializar la variable en el constructor.

En cuanto a los problemas de inicialización puedes, como te comenté, usar std::array y acompañarlo de las listas de inicialización propias de C++11.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #5 (permalink)  
Antiguo 11/04/2016, 07:43
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 8 meses
Puntos: 3
Respuesta: Inicializar array de cadenas en constructor

Tengo otro array pero es algo como:
Código C++:
Ver original
  1. private:
  2.    const char cadena [];
Y si hago en el constructor:
Código C++:
Ver original
  1. cadena="Hola mundo";
Ahí no hay problemas y se inicializa correctamente pero con un array de cadenas no me deja o no veo la manera correcta de hacerlo.
  #6 (permalink)  
Antiguo 11/04/2016, 08:00
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: Inicializar array de cadenas en constructor

Compilado bajo C++98:
Código C++:
Ver original
  1. struct POO
  2. {
  3.     const std::string test[10];
  4.  
  5.     POO();
  6. };
  7.  
  8. POO::POO()
  9.  : test( {"1","2","3","4","5","6","7","8","9","10" })
  10. { }
  11.  
  12. int main()
  13. {
  14.     POO p;
  15.     std::cout << p.test[5];
  16. }

Compilado bajo C++11:
Código C++:
Ver original
  1. struct POO
  2. {
  3.     const std::string test[10];
  4.  
  5.     POO();
  6. };
  7.  
  8. POO::POO()
  9.  : test{"1","2","3","4","5","6","7","8","9","10" }
  10. { }
  11.  
  12. int main()
  13. {
  14.     POO p;
  15.     std::cout << p.test[5];
  16. }

No funciona esto mismo con AnsiString??
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #7 (permalink)  
Antiguo 11/04/2016, 09:25
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 8 meses
Puntos: 3
Respuesta: Inicializar array de cadenas en constructor

Pues no se ni como hacerlo ya que mi constructor es asi:
Código C++:
Ver original
  1. __fastcall TForm1::TForm1(TComponent* Owner)
  2.    : TForm(Owner)
  3. {}
Todo lo que he probado incluso con std::string no lo acepta asi que ni idea y ademas tenemos el problema de que son dos arrays de cadenas con lo que tendria que inicializar asi 2 y que son con textos muy grandes y quedaría refeo jajaja.
Me parece increible lo complicado que pone C++ algo tan sencillo como eso .
  #8 (permalink)  
Antiguo 11/04/2016, 09:40
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: Inicializar array de cadenas en constructor

Cita:
Iniciado por aguml Ver Mensaje
Pues no se ni como hacerlo ya que mi constructor es asi:
Código C++:
Ver original
  1. __fastcall TForm1::TForm1(TComponent* Owner)
  2.    : TForm(Owner)
  3. {}
Y algo tal que...

Código C++:
Ver original
  1. __fastcall TForm1::TForm1(TComponent* Owner)
  2.        : TForm(Owner),
  3.          HintsMessages({"Este mensaje activa la ventana.",
  4.                         "Este mensaje pone el foco en la ventana.",
  5.                                // ...
  6.                                })
  7.     {}

Esto, claro está, asumiendo que has quitado lo de static.

Cita:
Iniciado por aguml Ver Mensaje
Todo lo que he probado incluso con std::string no lo acepta asi que ni idea y ademas tenemos el problema de que son dos arrays de cadenas con lo que tendria que inicializar asi 2 y que son con textos muy grandes y quedaría refeo jajaja.
¿Has probado a poner una clase aparte para proporcionar esas cadenas?

No se, se me ocurre quizás algo tal que:

Código C++:
Ver original
  1. class Messages
  2. {
  3.   static const AnsiString WindowIsActive;
  4.   static const AnsiString AnotherOne;
  5.   // ...
  6. };
  7.  
  8. const AnsiString Messages::WindowIsActive = "Este mensaje activa la ventana.";
  9. // ...

O incluso usar enumerados

Código C++:
Ver original
  1. enum Messages
  2. {
  3.   WindowIsActive,
  4.   AnotherOne,
  5.   // ...
  6. }
  7.  
  8. AnsiString GetMessage(Messages id)
  9. {
  10.   switch( id )
  11.   {
  12.     case WindowIsActive:
  13.       return "Este mensaje activa la ventana.";
  14.     // ...
  15.   }
  16. }

Cita:
Iniciado por aguml Ver Mensaje
Me parece increible lo complicado que pone C++ algo tan sencillo como eso .
Y no es que C++ ponga esto demasiado complicado, es que te falta base para entender correctamente cómo funcionan los constructores. Quizás sería recomendable dedicar unas horas a entender su funcionamiento.

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #9 (permalink)  
Antiguo 11/04/2016, 10:07
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 8 meses
Puntos: 3
Respuesta: Inicializar array de cadenas en constructor

Ok, lo primero que pones no funciona.
Lo demas que indicas no lo veo, para eso hago esto:
Código C++:
Ver original
  1. private:
  2.    static const char *HintsMessages[18],*HintsMessagesTypes[2];

Código C++:
Ver original
  1. const char* TForm1::HintsMessages[18] = {"Este mensaje activa la ventana.",
  2.                                          "Este mensaje pone el foco en la ventana.",
  3.                                          "Este mensaje quita el foco de la ventana.",
  4.                                          "Este mensaje indica si se redibuja la ventana o no.",
  5.                                          "Este mensaje se envia para preguntar a una ventana si se puede cerrar al cerrar sesión.",
  6.                                          "Este mensaje se envia para indicar a una ventana que se va a cerrar sesión.",
  7.                                          "Este mensaje envia un clic izquierdo.",
  8.                                          "Este mensaje es el que se da al pulsar el botón izquierdo del ratón.",
  9.                                          "Este mensaje es el que se da al soltar el botón izquierdo del ratón.",
  10.                                          "Este mensaje es el que se da al hacer doble clic con el botón izquierdo del ratón.",
  11.                                          "Este mensaje es el que se da al pulsar el botón derecho del ratón.",
  12.                                          "Este mensaje es el que se da al soltar el botón derecho del ratón.",
  13.                                          "Este mensaje es el que se da al hacer doble clic con el botón derecho del ratón.",
  14.                                          "Este mensaje es el que se da al pulsar el botón central del ratón.",
  15.                                          "Este mensaje es el que se da al soltar el botón central del ratón.",
  16.                                          "Este mensaje es el que se da al hacer doble clic con el botón central del ratón.",
  17.                                          "Este mensaje es el que se da al girar la rueda vertical del ratón.",
  18.                                          "Este mensaje es el que se da al girar la rueda horizontal del ratón."};
  19.  
  20. const char* TForm1::HintsMessagesTypes[2] = {"Esta opción espera la respuesta. El valor de retorno será la respuesta obtenida.",
  21.                                              "Esta opción no espera respuesta alguna. Retorna 1 si se envió correctamente y 0 si falló."};
  22. //---------------------------------------------------------------------------
  23. __fastcall TForm1::TForm1(TComponent* Owner)
  24.    : TForm(Owner)
  25. {
  26.    //Inicializo la cadena constante de validacion de entrada del teclado
  27.    GoodKey = "0123456789abcdefABCDEF";
  28. }
Esto funciona pero no se que tan correcto será.
Otra opcion antes de crearme mi propia clase para eso seria usar por ejemplo TStrings de C++Builder e ir añadiendo uno a uno todos los miembros y seria algo asi:
Código C++:
Ver original
  1. TStrings *HintsMessagesTypes;
  2. HintsMessagesTypes=new TListStrings;
  3. HintsMessagesTypes->Add("Esta opción espera la respuesta. El valor de retorno será la respuesta obtenida.");
  4. HintsMessagesTypes->Add("Esta opción no espera respuesta alguna. Retorna 1 si se envió correctamente y 0 si falló.");
Eso lo hago en el evento OnCreate del form y en el OnClose o en el OnDestroy hago:
Código C++:
Ver original
  1. HintsMessagesTypes->Clear();
  2. delete HintsMessageTypes;
No lo hago asi por lo engorroso que es el tener que estar gestionando la memoria dinamica y los problemas que puede dar al correr en un pc que no tenga suficiente memoria libre y tenga que crear items en tiempo de ejecucion mientras que lo que yo intento ya ocupen una memoria y no soliciten mas al arrancar. Creo que la unica forma es como lo he hecho con static o al menos la unica que me ha funcionado.
  #10 (permalink)  
Antiguo 11/04/2016, 10:24
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: Inicializar array de cadenas en constructor

Cita:
Iniciado por aguml Ver Mensaje
Ok, lo primero que pones no funciona.
Sin saber cómo lo estás escribiendo tu y sin conocer la versión de C++ sobre la que estás compilando es complicado dar respuestas más concretas.

Cita:
Iniciado por aguml Ver Mensaje
Lo demas que indicas no lo veo, para eso hago esto:

...

Esto funciona pero no se que tan correcto será.
Yo lo denominaría como algo tan engorroso o incluso más que las soluciones que te propongo.

Cita:
Iniciado por aguml Ver Mensaje
Otra opcion antes de crearme mi propia clase para eso seria usar por ejemplo TStrings de C++Builder e ir añadiendo uno a uno todos los miembros y seria algo asi:

...

No lo hago asi por lo engorroso que es el tener que estar gestionando la memoria dinamica y los problemas que puede dar al correr en un pc que no tenga suficiente memoria libre y tenga que crear items en tiempo de ejecucion mientras que lo que yo intento ya ocupen una memoria y no soliciten mas al arrancar.
La gestión de textos en una aplicación siempre es una tarea engorrosa. No todo en la programación iba a ser bonito y agradable de hacer.

En cuanto al tema de la memoria... no se, salvo que trabajes con un 386 con 32MB de RAM no se me ocurre cómo puedes llenar la memoria dinámica a base de textos. Las opciones que te he propuesto cuidan de no repetir cadenas, de tal forma que el consumo de memoria se reduce tanto como usando static.

Cita:
Iniciado por aguml Ver Mensaje
Creo que la unica forma es como lo he hecho con static o al menos la unica que me ha funcionado.
Si tienes una forma que te funciona y no hay razones de peso para cambiarla usa esa. Para cambiarla por algo mejor siempre tendrás tiempo en el futuro (sobretodo si el diseño es bueno).

Volviendo al tema de las soluciones que te he propuesto has de tener en cuenta que crear clases es prácticamente gratis en C++. ¿Que empiezas a tener muchos archivos en el proyecto? Lo mismo empieza a tener sentido montarse un sistema de documentación con doxygen para no tener que abrir cada dos por tres los ficheros a ver qué tienen dentro... pero vamos que no te de pereza crear clases para lo que necesites.

Por otro lado, tener clases separadas te puede ayudar a evitar duplicados, en tu caso, textos que se repitan en varias ventanas.

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #11 (permalink)  
Antiguo 11/04/2016, 15:13
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 8 meses
Puntos: 3
Respuesta: Inicializar array de cadenas en constructor

Pensándolo, para cadenas constantes ¿es una mala práctica que sean globales?

Etiquetas: cadena, cadenas, char, constructor, inicializar, string
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 04:53.