Devemos adicionar construtores às estruturas?

13

Geralmente usamos estruturas c ++ para definir a estrutura de dados em oposição à classe, que pode ser um módulo completo com métodos membros. Agora, no fundo, sabemos que ambos são os mesmos (falando vagamente).

O fato de frequentemente usarmos / tratarmos estruturas como entidades apenas de dados cria essa necessidade de não adicionarmos construtores padrão também. Mas os construtores são sempre ótimos, eles simplificam as coisas e ajudam a eliminar erros.

Seria desaprovado se adicionar construtores padrão às minhas estruturas de dados?

O construtor padrão de implementação também cria a estrutura Non-POD (tipo de dados antigo simples), desde que outros critérios sejam atendidos?

Para colocar as coisas em perspectiva, considere um exemplo simples, mas, na realidade, a estrutura seria muito maior.

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

Toda vez que crio um método, tenho que me preocupar (para dizer o mínimo) se esqueci de definir algum valor. Imagine que eu esqueço de definir temperaturee aplicar o método ao sistema, que agora é um valor alto aleatório e causa confusão. Ou eu esqueci de definir duratione agora o método se aplica por uma alta duração desconhecida.

Por que eu deveria assumir a responsabilidade de inicializar o objeto todas as vezes em vez de implementar seu construtor que o garante?

zadane
fonte
Se você precisar impor que apenas certos valores sejam permitidos, não terá um tipo de dados antigo simples. Se você quiser apenas maneiras convenientes de inicializar estruturas, funções antigas simples farão isso.
Doval
Depende do que esses construtores estão fazendo. Eu acho que é completamente razoável ter um construtor em uma estrutura simples, se apenas definir valores de campo de maneiras básicas.
Gort the Robot
@ Doval essa não é a questão, eu atualizei o post. Steven: sim, os construtores apenas atribuirão valores padrão.
Zadane 11/11
@StevenBurnap: Se o construtor fizer algo mais do que apenas definir valores de campo de maneiras básicas, é apenas mais apropriado tê-lo. Mesmo em uma estrutura.
Jan Hudec
2
O que quero dizer é que, se você começar a encontrar lógica complicada no construtor, é provável que você a torne uma classe. (IMHO) Mas é realmente apenas uma questão de estilo, como a única diferença real entre structe classé que um é o padrão para privado e o outro para público.
Gort the Robot

Respostas:

13

Às vezes é apropriado adicionar construtor a uma estrutura e outras não.

A adição de construtor (qualquer construtor) a uma estrutura impede o uso de inicializador agregado. Portanto, se você adicionar um construtor padrão, também precisará definir um construtor não padrão, inicializando os valores. Mas se você deseja garantir que sempre inicialize todos os membros, é apropriado.

A adição de construtor (qualquer construtor, novamente) o torna não POD, mas no C ++ 11 a maioria das regras que anteriormente se aplicavam ao POD foram alteradas para se aplicarem aos objetos de layout padrão e a adição de construtores não quebra isso. Portanto, o inicializador agregado é basicamente a única coisa que você perde. Mas também costuma ser uma grande perda.

Jan Hudec
fonte
8

Com o C ++ 11, você pode fazer

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

E sempre que você esquece de inicializar algo, você obtém a inicialização padrão.

Vorac
fonte
-1

Resposta rápida:

Depende do que você deseja alcançar.

Resposta longa, prolongada e chata:

Você acertou em cheio.

Normalmente não gosto que "C ++" permita que "Struct (s)" permita declarar métodos. De preferência, eu uso "Class (es)" explícita (s) para os métodos necessários e "Struct (s)" (POD) "apenas para campos.

No entanto, concordo que algumas operações simples básicas, como:

  • atribuir valores iniciais ("construtor")
  • faça uma cópia de uma estrutura ("construtor de cópias)
  • atribuir valores a uma estrutura existente ("operador de atribuição de sobrecarga")

São necessários e, nessas circunstâncias, métodos para estruturas, fazem sentido.

Sugestão

Outra solução potencial é usar estruturas de POD, mas, ainda assim, tratá-las conceitualmente como classes e objetos.

Coloque essas declarações em um espaço para nome e adicione funções globais para as ações mais importantes.

A declaração de código pode ser semelhante a esta:

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

O código que aplica a solução pode ser algo como isto:

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

Essa abordagem alternativa é melhor quando é necessária uma grande alocação de dados na memória ou na interação com outras bibliotecas compartilhadas de baixo nível.

Essa abordagem, com algumas alterações, é aplicada no desenvolvimento de jogos.

Extra

Pessoalmente, considero uma extensão de sintaxe para "C ++" ou mesmo um novo PL baseado em "C ++" que resolve esse 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

Felicidades.

umlcat
fonte