Чи слід додати конструктори до конструкцій?


14

Ми часто використовуємо структури c ++ для визначення структури даних на відміну від класу, який може бути повним модулем з методами-членами. Тепер у глибині душі ми знаємо, що вони обоє однакові (слабко кажучи).

Той факт, що ми часто використовуємо / трактуємо структури як сукупності лише для даних, створює це заклик до того, що ми також не додаємо конструкторів за замовчуванням. Але конструктори завжди чудові, вони спрощують справи і допомагають усунути помилки.

Чи нахмуриться це, якщо до моїх даних даних додати конструктори за замовчуванням?

Чи реалізує конструктор за замовчуванням також структуру Non-POD (звичайний старий тип даних) за умови дотримання інших критеріїв?

Щоб поставити речі в перспективу, розглянемо простий приклад, але насправді структура буде набагато більшою.

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

Кожен раз, коли я створюю метод, мені доводиться хвилюватися (якщо не менше), якщо я забув встановити якесь значення. Уявіть, що я забув встановити temperatureі застосувати метод до системи, яка зараз є випадково високою цінністю і спричиняє хаос. Або я забув встановити, durationі тепер метод застосовується для невідомо великої тривалості.

Чому я повинен брати на себе відповідальність за ініціалізацію об'єкта щоразу, а не впроваджувати його конструктор, який це гарантує?


Якщо вам потрібно встановити, що дозволено лише певні значення, то у вас не зовсім звичайний старий тип даних. Якщо ви просто хочете зручні способи ініціалізації структур, це робитимуть звичайні старі функції.
Doval

Це залежить від того, що роблять ці конструктори. Я думаю, що цілком розумно мати конструктор на простій структурі, якщо це просто встановлення значень поля основними способами.
Gort the Robot

@Doval це не питання, я оновив пост. Стівен: так, конструктори будуть лише призначати значення за замовчуванням.
задане

@StevenBurnap: Якщо конструктор нічого не робить більше , ніж просто установки значень полів в основних способах це тільки більш доречно його. Навіть на структурі.
Ян Худек

2
Що я маю на увазі, якщо ви почнете знаходити складну логіку в конструкторі, швидше за все, вам слід перетворити його на клас. (ІМХО) Але це дійсно тільки питання стилю , як тільки дійсне розходження між structі classє те , що один з замовчуванням приватних і інша громадськості.
Gort the Robot

Відповіді:


13

Іноді доречно додати конструктор до структури, а іноді - ні.

Додавання конструктора (будь-якого конструктора) до структури перешкоджає використанню на ньому сукупного ініціалізатора. Отже, якщо ви додаєте конструктор за замовчуванням, вам також доведеться визначити конструктор, який не використовується за замовчуванням, ініціалізуючи значення. Але якщо ви хочете, щоб ви завжди ініціалізували всіх членів, це доречно.

Додавання конструктора (знову ж таки, будь-який конструктор) робить його не POD, але в C ++ 11 більшість правил, які раніше застосовувались лише до POD, були змінені на стандартні об'єкти компонування, і додавання конструкторів цього не порушує. Тож ініціалізатор сукупності - це єдине, що ви втрачаєте. Але це також часто велика втрата.


8

З C ++ 11 ви можете це зробити

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

І кожного разу, коли ви забудете щось ініціалізувати, ви отримуєте ініціалізацію за замовчуванням.


-1

Швидкий відповідь:

Це залежить від того, чого ви хочете досягти.

Довга, розширена, нудна відповідь:

Ти вдарив цвях.

Зазвичай мені не подобається, що "C ++" дозволяє "Struct (s)" дозволяє оголошувати методи. Переважно, я використовую явні "Клас (и)" для необхідних методів, і "Структури (и)" POD лише для полів.

Але я погоджуюся з деякими основними простими операціями, такими як:

  • призначити початкові значення ("конструктор")
  • зробити копію структури ("конструктор копій")
  • призначити значення існуючій структурі ("оператор присвоєння перевантаження")

Потрібні, і в цих умовах методи для структур мають сенс.

Пропозиція

Ще одне потенційне рішення - використовувати структури POD, але, все ще концептуально, трактуйте їх як класи та об'єкти.

Оберніть ці декларації в простір імен та додайте глобальні функції для найважливіших дій.

Декларація коду може бути подібною до цієї:

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

Код, який застосовує рішення, може бути приблизно таким:

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

Цей альтернативний підхід є кращим, коли потрібен величезний розподіл пам’яті даних або взаємодія з іншими спільно використовуваними бібліотеками низького рівня.

Цей підхід, з деякими змінами, застосовується в ігровій розробці.

Додатково

Особисто я розглядаю розширення синтаксису для "C ++" або навіть нового PL на базі "C ++", який вирішує цю проблему:

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

Ура.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.