¿Deberíamos agregar constructores a las estructuras?

13

A menudo usamos las estructuras c ++ para definir la estructura de datos en lugar de la clase, que puede ser un módulo completo con métodos de miembro. Ahora, en el fondo, sabemos que ambos son iguales (hablando en términos generales).

El hecho de que a menudo usamos / tratamos las estructuras como entidades de solo datos crea la necesidad de que no agreguemos constructores predeterminados también. Pero los constructores siempre son excelentes, simplifican las cosas y ayudan a eliminar errores.

¿Estaría mal visto si añadiera constructores predeterminados a mis estructuras de datos?

¿La implementación del constructor predeterminado también hace que la estructura Non-POD (tipo de datos sin formato antiguo) siempre que se cumplan otros criterios?

Para poner las cosas en perspectiva, considere un ejemplo simple pero en realidad la estructura sería mucho más grande.

struct method
{
    char    name[32];
    float   temperature;
    int     duration;
};

Cada vez que creo un método, tengo que preocuparme (por decir lo menos) si olvidé establecer algún valor. Imagínese que me olvido de configurar temperature y aplicar el método al sistema que ahora tiene un valor alto aleatorio y causa caos. O me olvidé de establecer duration y ahora el método se aplica solo a una duración alta desconocida.

¿Por qué debería asumir la responsabilidad de inicializar el objeto cada vez en lugar de implementar su constructor que lo garantiza?

    
pregunta zadane 11.11.2014 - 17:51

3 respuestas

13

A veces es apropiado agregar un constructor a una estructura y otras no.

Agregar constructor (cualquier constructor) a una estructura evita usar el inicializador agregado en él. Por lo tanto, si agrega un constructor predeterminado, también deberá definir el constructor no predeterminado que inicializa los valores. Pero si desea asegurarse de que siempre inicializa todos los miembros, es apropiado.

Agregar constructor (cualquier constructor, nuevamente) hace que no sea POD, pero en C ++ 11, la mayoría de las reglas que anteriormente se aplicaban a POD solo se modificaron para aplicar a los objetos de diseño estándar y agregar constructores no rompe eso. Así que el inicializador agregado es básicamente lo único que se pierde. Pero a menudo también es una gran pérdida.

    
respondido por el Jan Hudec 11.11.2014 - 18:29
8

Con C ++ 11 puede hacer

struct method
{
    char    name[32] {};
    float   temperature = 42.141521;
    int     duration = -6;
};

Y cada vez que olvida inicializar algo, obtiene la inicialización predeterminada.

    
respondido por el Vorac 13.11.2014 - 17:08
-1

Respuesta rápida:

Depende de lo que quieras lograr.

Respuesta larga, extendida y aburrida:

Has golpeado el clavo.

Por lo general, no me gusta que "C ++" permita que "Struct (s)" permita declarar métodos. Preferiblemente, uso "Clase (s) explícita" para los métodos requeridos y P.O.D. "Struct (s)" solo para campos.

Sin embargo, estoy de acuerdo en que algunas operaciones básicas simples, como:

  • asignar valores iniciales ("constructor")
  • hacer una copia de una estructura ("constructor de copia)
  • asignar valores a una estructura existente ("operador de asignación de sobrecarga")

Son necesarios y, en esas circunstancias, los métodos para las estructuras tienen sentido.

Sugerencia

Otra solución potencial es usar P.O.D. estructuras, pero, aún así, conceptualmente tratarlos como clases y objetos.

Envuelva esas declaraciones en un espacio de nombres y agregue funciones globales para las acciones más importantes.

La declaración de código podría ser similar a esto:

namespace Customers
{
  struct CustomerStruct
  {
    char[255] FirstName;
    char[255] LastName;
    int Age;
    bool IsAlive;
    bool IsMarried;
  }; // struct

  CustomerStruct* CreateCustomer
  (
    char* NewFirstName;
    char* NewLastName;
    int NewAge;
    bool NewIsAlive;
    bool NewIsMarried;
  )
  {
    CustomerStruct* NewCustomer = new CustomerStruct();
      NewCustomer->FirstName = NewFirstName;
      NewCustomer->LastName = NewLastName;
      NewCustomer->Age = NewAge;
      NewCustomer->IsAlive = NewIsAlive;
      NewCustomer->IsMarried = NewIsMarried;
    return NewCustomer;
  } // CustomerStruct* CreateCustomer (...)

} // namespace

El código que aplica la solución, podría ser algo como esto:

#include <Customers>

using Customers;

int main (...)
{
   int ErrorCode = 0;

   CustomerClass* ThisCustomer =
     Customers::CreateCustomer
      ("John", "Doe", 23, true, true);

   // do something with "ThisCustomer"

   delete ThisCustomer;

   return ErrorCode;
} // int main(...)

Este enfoque alternativo es mejor cuando se requiere una gran asignación de datos en memoria o cuando se interactúa con otras bibliotecas compartidas de bajo nivel.

Este enfoque, con algunos cambios, se aplica en Desarrollo de juegos.

Extra

Personalmente, considero una extensión de sintaxis para "C ++", o incluso, una nueva P.L basada en "C ++". que resuelve este problema:

// "Plain Old Data" Structure
// No Methods, No "Functors", allowed
strict struct CustomerStruct
{
  char[255] FirstName;
  char[255] LastName;
  int Age;
  bool IsAlive;
  bool IsMarried;
}; // strict struct

// Object Oriented "Plain Old Data" Structure
// Yes, Methods and "Functors" allowed
relaxed struct CustomerStruct
{
  char[255] FirstName;
  char[255] LastName;
  int Age;
  bool IsAlive;
  bool IsMarried;

  public void Foo();
  public void Bar();

  public (void*) (SomeFunctor) ();
}; // relaxed struct

// Class and Object Oriented
class CustomerClass
{
  public char[255] FirstName;
  public char[255] LastName;
  public int Age;
  public bool IsAlive;
  public bool IsMarried;

  public void Foo();
  public void Bar();
}; // class

Saludos.

    
respondido por el umlcat 11.11.2014 - 19:45

Lea otras preguntas en las etiquetas