Dovremmo aggiungere costruttori alle strutture?


14

Usiamo spesso le strutture c ++ per definire la struttura dei dati rispetto alla classe che può essere un modulo completo con metodi membri. Ora in fondo, sappiamo che entrambi sono uguali (parlando liberamente).

Il fatto che spesso utilizziamo / trattiamo le strutture come entità solo dati crea questo impulso a non aggiungere anche costruttori predefiniti. Ma i costruttori sono sempre fantastici, rendono le cose più semplici e aiutano a eliminare gli errori.

Sarebbe disapprovato se aggiungere costruttori predefiniti alle mie strutture di dati?

L'implementazione del costruttore predefinito rende anche la struttura Non-POD (semplice vecchio tipo di dati) purché siano soddisfatti altri criteri?

Per mettere le cose in prospettiva, considera un semplice esempio ma in realtà la struttura sarebbe molto più grande.

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

Ogni volta che creo un metodo, devo preoccuparmi (per non dire altro) se ho dimenticato di impostare un valore. Immagina di dimenticare di impostare temperaturee applicare il metodo al sistema che ora è un valore casuale elevato e causa caos. Oppure ho dimenticato di impostare duratione ora il metodo si applica per una durata sconosciuta.

Perché dovrei assumermi la responsabilità di inizializzare l'oggetto ogni volta invece di implementare il suo costruttore che lo garantisce?


Se è necessario imporre che siano consentiti solo determinati valori, non si dispone di un vecchio tipo di dati. Se vuoi solo modi convenienti di inizializzare le strutture, lo faranno le semplici vecchie funzioni.
Doval,

Dipende da cosa stanno facendo questi costruttori. Penso che sia del tutto ragionevole avere un costruttore su una struttura semplice se si stanno semplicemente impostando i valori di campo in modi di base.
Gort il robot l'

@Doval non è questa la domanda, ho aggiornato il post. Steven: sì, i costruttori assegneranno solo valori predefiniti.
zadane,

@StevenBurnap: se il costruttore fa qualcosa di più della semplice impostazione dei valori di campo in modi di base, è più appropriato averlo. Anche su una struttura.
Jan Hudec,

2
Quello che voglio dire è che se inizi a trovare una logica complicata nel costruttore, è probabile che tu debba trasformarla in una classe. (IMHO) Ma in realtà è solo una domanda di stile, in quanto l'unica vera differenza tra structed classè che uno di default è privato e l'altro è pubblico.
Gort il robot l'

Risposte:


13

A volte è appropriato aggiungere il costruttore a una struttura, a volte no.

L'aggiunta di un costruttore (qualsiasi costruttore) a una struttura impedisce di utilizzare l'inizializzatore aggregato su di essa. Quindi, se aggiungi un costruttore predefinito, dovrai anche definire un costruttore non predefinito inizializzando i valori. Ma se vuoi assicurarti di inizializzare sempre tutti i membri, è appropriato.

L'aggiunta del costruttore (qualsiasi costruttore, di nuovo) lo rende non-POD, ma in C ++ 11 la maggior parte delle regole precedentemente applicate al POD sono state modificate per applicarsi agli oggetti di layout standard e l'aggiunta di costruttori non lo interrompe. Quindi l'inizializzatore aggregato è praticamente l'unica cosa che perdi. Ma è anche spesso una grande perdita.


8

Con C ++ 11 puoi farlo

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

E ogni volta che si dimentica di inizializzare qualcosa, si ottiene l'inizializzazione predefinita.


-1

Risposta rapida:

Dipende da cosa vuoi ottenere.

Risposta lunga, estesa, noiosa:

Hai colpito l'unghia.

Di solito non mi piace che "C ++" consenta che "Struct (s)" consenta di dichiarare metodi. Preferibilmente, uso esplicite "Class (es)" per i metodi richiesti e POD "Struct (s)" per i soli campi.

Tuttavia, sono d'accordo che alcune semplici operazioni di base, come:

  • assegnare valori iniziali ("costruttore")
  • fare una copia di una struttura ("costruttore di copia)
  • assegnare valori a una struttura esistente ("sovraccarico assegnare operatore")

Sono richiesti e, in tali circostanze, hanno senso i metodi per le strutture.

Suggerimento

Un'altra potenziale soluzione consiste nell'utilizzare le strutture POD, ma, concettualmente, trattarle come classi e oggetti.

Avvolgi quelle dichiarazioni in uno spazio dei nomi e, aggiungi le funzioni globali, per le azioni più importanti.

La dichiarazione del codice potrebbe essere simile a questa:

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

Il codice che applica la soluzione, potrebbe essere qualcosa del genere:

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

Questo approccio alternativo è migliore quando è richiesta un'enorme allocazione di memoria di dati o interagendo con altre librerie condivise di basso livello.

Questo approccio, con alcune modifiche, viene applicato nello sviluppo del gioco.

Extra

Personalmente, considero un'estensione di sintassi per "C ++", o anche, un nuovo PL basato su "C ++" che risolve questo 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

Saluti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.