Faut-il ajouter des constructeurs aux structures?

14

Nous utilisons souvent des structures c ++ pour définir la structure des données par opposition à la classe qui peut être un module complet avec des méthodes membres. Maintenant, au fond, nous savons que les deux sont les mêmes (en gros).

Le fait que nous utilisons / traitons souvent les structures en tant qu'entités de données uniquement crée cette envie de ne pas ajouter également de constructeurs par défaut. Mais les constructeurs sont toujours super, ils simplifient les choses et aident à éliminer les erreurs.

Serait-il mal vu si j'ajoutais des constructeurs par défaut à mes structures de données?

L'implémentation du constructeur par défaut rend-elle également la structure Non-POD (type de données ancien simple) à condition que d'autres critères soient remplis?

Pour mettre les choses en perspective, considérons un exemple simple mais en réalité la structure serait beaucoup plus grande.

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

Chaque fois que je crée une méthode, je dois m'inquiéter (pour dire le moins) si j'oublie de définir une valeur. Imaginez que j'oublie de définir temperatureet d'appliquer la méthode au système qui est maintenant une valeur élevée aléatoire et provoque le chaos. Ou j'ai oublié de définir durationet maintenant la méthode s'applique elle-même pour une durée élevée inconnue.

Pourquoi devrais-je prendre la responsabilité d'initialiser l'objet à chaque fois au lieu d'implémenter son constructeur qui le garantit?

zadane
la source
Si vous devez faire en sorte que seules certaines valeurs soient autorisées, vous n'avez pas tout à fait un ancien type de données simple. Si vous voulez juste des moyens pratiques d'initialiser des structures, les anciennes fonctions simples le feront.
Doval
Cela dépend de ce que font ces constructeurs. Je pense qu'il est tout à fait raisonnable d'avoir un constructeur sur une structure simple s'il s'agit simplement de définir des valeurs de champ de manière basique.
Gort the Robot
@Doval ce n'est pas la question, j'ai mis à jour le message. Steven: oui, les constructeurs n'attribueront que des valeurs par défaut.
zadane
@StevenBurnap: Si le constructeur fait autre chose que de simplement définir des valeurs de champ de manière simple, il est plus approprié de l'avoir. Même sur une structure.
Jan Hudec
2
Ce que je veux dire, c'est que si vous commencez à trouver une logique compliquée dans le constructeur, il est probable que vous devriez en faire une classe. (À mon humble avis) Mais c'est vraiment juste une question de style car la seule différence réelle entre structet classest que l'un par défaut est privé et l'autre public.
Gort le robot

Réponses:

13

Parfois, il est approprié d'ajouter un constructeur à une structure et parfois ce n'est pas le cas.

L'ajout d'un constructeur (n'importe quel constructeur) à une structure empêche d'utiliser un initialiseur d'agrégat dessus. Donc, si vous ajoutez un constructeur par défaut, vous devrez également définir un constructeur non par défaut initialisant les valeurs. Mais si vous voulez vous assurer que vous initialisez toujours tous les membres, c'est approprié.

L'ajout de constructeur (n'importe quel constructeur, encore une fois) le rend non POD, mais en C ++ 11 la plupart des règles qui s'appliquaient auparavant au POD uniquement ont été modifiées pour s'appliquer aux objets de disposition standard et l'ajout de constructeurs ne rompt pas cela. Donc, l'initialiseur d'agrégat est fondamentalement la seule chose que vous perdez. Mais c'est aussi souvent une grosse perte.

Jan Hudec
la source
8

Avec C ++ 11, vous pouvez faire

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

Et chaque fois que vous oubliez d'initialiser quelque chose, vous obtenez l'initialisation par défaut.

Vorac
la source
-1

Réponse rapide:

Cela dépend de ce que vous voulez réaliser.

Réponse longue, longue et ennuyeuse:

Vous frappez le clou.

Je n'aime généralement pas que "C ++" autorise "Struct (s)" permet de déclarer des méthodes. De préférence, j'utilise des "classes" explicites pour les méthodes requises et des "structures (s)" POD pour les seuls champs.

Pourtant, je conviens que certaines opérations simples de base, comme:

  • attribuer des valeurs initiales ("constructeur")
  • faire une copie d'une structure ("constructeur de copie)
  • attribuer des valeurs à une structure existante ("opérateur d'affectation de surcharge")

Sont nécessaires et, dans ces circonstances, des méthodes pour les structures ont du sens.

Suggestion

Une autre solution potentielle consiste à utiliser des structures POD, mais en les traitant toujours conceptuellement comme des classes et des objets.

Enveloppez ces déclarations dans un espace de noms et ajoutez des fonctions globales pour les actions les plus importantes.

La déclaration de code pourrait être similaire à ceci:

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

Le code qui applique la solution pourrait ressembler à ceci:

#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(...)

Cette approche alternative est meilleure lorsqu'une énorme allocation de mémoire de données est requise ou en interaction avec d'autres bibliothèques partagées de bas niveau.

Cette approche, avec quelques modifications, est appliquée dans le développement de jeux.

Supplémentaire

Personnellement, je considère une extension de syntaxe pour "C ++", ou même, un nouveau PL basé sur "C ++" qui résout ce problème:

// "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

À votre santé.

umlcat
la source