Sollten wir Konstruktoren zu Strukturen hinzufügen?

13

Wir verwenden häufig c ++ - Strukturen, um die Datenstruktur im Gegensatz zur Klasse zu definieren, die ein vollständiges Modul mit Member-Methoden sein kann. Tief im Inneren wissen wir, dass beide gleich sind (grob gesagt).

Die Tatsache, dass wir häufig Strukturen als reine Datenentitäten verwenden / behandeln, erzeugt diesen Drang, dass wir auch keine Standardkonstruktoren hinzufügen. Aber Konstruktoren sind immer großartig, sie vereinfachen die Dinge und helfen, Fehler zu beseitigen.

Wäre es verpönt, meinen Datenstrukturen Standardkonstruktoren hinzuzufügen?

Wird durch die Implementierung des Standardkonstruktors auch die Struktur Non-POD (normaler alter Datentyp) erstellt, sofern andere Kriterien erfüllt sind?

Um die Dinge in die richtige Perspektive zu rücken, betrachten Sie ein einfaches Beispiel, aber in Wirklichkeit wäre die Struktur viel größer.

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

Jedes Mal, wenn ich eine Methode erstelle, muss ich mir Sorgen machen, wenn ich vergessen habe, einen Wert festzulegen. Stellen Sie sich vor, ich vergesse, temperaturedie Methode festzulegen und auf ein System anzuwenden, das jetzt einen zufälligen hohen Wert hat und Chaos verursacht. Oder ich habe vergessen einzustellen durationund nun wendet sich die Methode für eine unbekannt hohe Dauer an.

Warum sollte ich die Verantwortung übernehmen, das Objekt jedes Mal zu initialisieren, anstatt seinen Konstruktor zu implementieren, der es garantiert?

Zadane
quelle
Wenn Sie durchsetzen müssen, dass nur bestimmte Werte zulässig sind, haben Sie keinen einfachen alten Datentyp. Wenn Sie nur bequeme Möglichkeiten zum Initialisieren von Strukturen wünschen, werden dies einfache alte Funktionen tun.
Doval
Es hängt davon ab, was diese Konstruktoren tun. Ich denke, es ist völlig vernünftig, einen Konstruktor für eine einfache Struktur zu haben, wenn es nur darum geht, Feldwerte auf einfache Weise festzulegen.
Gort the Robot
@Doval das ist nicht die frage, ich aktualisiere den post. Steven: Ja, die Konstruktoren werden nur Standardwerte zuweisen.
Zadane
@StevenBurnap: Wenn der Konstruktor etwas mehr als nur Feldwerte in grundlegenden Möglichkeiten Einstellung ist es nur mehr angebracht , sie zu haben. Sogar auf einer Struktur.
Jan Hudec
2
Was ich meine ist, wenn Sie anfangen, komplizierte Logik im Konstruktor zu finden, ist es wahrscheinlich, dass Sie es in eine Klasse verwandeln sollten. (IMHO) Aber es ist wirklich nur eine Stilfrage, da der einzige tatsächliche Unterschied zwischen structund darin classbesteht, dass die eine standardmäßig privat und die andere öffentlich ist.
Gort the Robot

Antworten:

13

Manchmal ist es angebracht, einer Struktur einen Konstruktor hinzuzufügen, manchmal nicht.

Durch Hinzufügen eines Konstruktors (eines beliebigen Konstruktors) zu einer Struktur wird die Verwendung des Aggregatinitialisierers verhindert. Wenn Sie also einen Standardkonstruktor hinzufügen, müssen Sie auch einen Nicht-Standardkonstruktor definieren, der die Werte initialisiert. Wenn Sie jedoch sicherstellen möchten, dass Sie immer alle Mitglieder initialisieren, ist dies angemessen.

Durch Hinzufügen eines Konstruktors (wieder eines beliebigen Konstruktors) wird dieser nicht als POD definiert. In C ++ 11 wurden jedoch die meisten Regeln, die zuvor nur für POD gelten, geändert, um auf Standardlayoutobjekte angewendet zu werden, und durch Hinzufügen von Konstruktoren wird dies nicht beeinträchtigt. Der Aggregatinitialisierer ist also im Grunde das Einzige, was Sie verlieren. Aber es ist auch oft ein großer Verlust.

Jan Hudec
quelle
8

Mit C ++ 11 ist das möglich

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

Und wenn Sie vergessen, etwas zu initialisieren, erhalten Sie die Standardinitialisierung.

Vorac
quelle
-1

Schnelle Antwort:

Es kommt darauf an, was Sie erreichen wollen.

Lange, ausgedehnte, langweilige Antwort:

Du hast den Nagel getroffen.

Ich mag normalerweise nicht, dass "C ++" erlaubt, dass "Struct (s)" Methoden deklariert. Vorzugsweise verwende ich explizite "Klassen" für erforderliche Methoden und POD "Strukturen" nur für Felder.

Ich stimme jedoch zu, dass einige grundlegende einfache Operationen, wie:

  • Anfangswerte zuweisen ("Konstruktor")
  • kopiere eine Struktur ("copy constructor")
  • Zuweisen von Werten zu einer vorhandenen Struktur ("Überladungszuweisungsoperator")

Sind erforderlich, und unter diesen Umständen sind Methoden für Strukturen sinnvoll.

Vorschlag

Eine andere mögliche Lösung besteht darin, POD-Strukturen zu verwenden, diese jedoch konzeptionell als Klassen und Objekte zu behandeln.

Schreiben Sie diese Deklarationen in einen Namespace und fügen Sie globale Funktionen für die wichtigsten Aktionen hinzu.

Die Code-Deklaration könnte etwa so aussehen:

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

Der Code, der die Lösung anwendet, könnte etwa so lauten:

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

Dieser alternative Ansatz ist besser, wenn eine große Speicherzuordnung von Daten erforderlich ist oder wenn mit anderen gemeinsam genutzten Bibliotheken auf niedriger Ebene interagiert werden soll.

Dieser Ansatz wird mit einigen Änderungen in der Spieleentwicklung angewendet.

Extra

Persönlich betrachte ich eine Syntaxerweiterung für "C ++" oder sogar eine neue "C ++" - basierte PL, die dieses Problem löst:

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

Prost.

umlcat
quelle