Haruskah kita menambahkan konstruktor ke struct?

14

Kami sering menggunakan c ++ struct untuk mendefinisikan struktur data sebagai lawan dari kelas yang dapat menjadi modul lengkap dengan metode anggota. Sekarang jauh di lubuk hati, kita tahu mereka berdua sama (secara longgar).

Fakta bahwa kita sering menggunakan / memperlakukan struct sebagai entitas data saja menciptakan desakan ini bahwa kita juga tidak menambahkan konstruktor default. Tetapi konstruktor selalu bagus, mereka membuat hal-hal sederhana dan membantu menghilangkan kesalahan.

Apakah akan disukai jika menambahkan konstruktor default ke struktur data saya?

Apakah menerapkan konstruktor default juga membuat struct Non-POD (tipe data lama biasa) asalkan kriteria lain terpenuhi?

Untuk menempatkan hal-hal dalam perspektif, pertimbangkan contoh sederhana tetapi dalam kenyataannya struct akan jauh lebih besar.

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

Setiap kali saya membuat metode, saya harus khawatir tentang (untuk sedikitnya) jika saya lupa menetapkan beberapa nilai. Bayangkan saya lupa mengatur temperaturedan menerapkan metode ke sistem yang sekarang menjadi nilai tinggi acak dan menyebabkan kekacauan. Atau saya lupa mengatur durationdan sekarang metode ini berlaku untuk durasi tinggi yang tidak diketahui.

Mengapa saya harus bertanggung jawab untuk menginisialisasi objek setiap kali alih-alih mengimplementasikan konstruktornya yang menjaminnya?

zadane
sumber
Jika Anda perlu memastikan bahwa hanya nilai-nilai tertentu yang diizinkan, maka Anda tidak memiliki tipe data lama yang sederhana. Jika Anda hanya ingin cara yang mudah untuk menginisialisasi struct, fungsi-fungsi lama yang biasa akan melakukan itu.
Doval
Tergantung pada apa yang dilakukan konstruktor ini. Saya pikir itu benar-benar masuk akal untuk memiliki konstruktor pada struct sederhana jika hanya menetapkan nilai-nilai bidang dengan cara dasar.
Gort the Robot
@Doval itu bukan pertanyaan, saya memperbarui posting. Steven: ya konstruktor hanya akan memberikan nilai default saja.
zadane
@StevenBurnap: Jika konstruktor melakukan sesuatu yang lebih dari sekadar menetapkan nilai bidang dengan cara-cara dasar, hanya lebih tepat untuk memilikinya. Bahkan pada struct.
Jan Hudec
2
Maksud saya adalah, jika Anda mulai menemukan logika yang rumit di konstruktor, kemungkinan Anda harus membuatnya menjadi kelas. (IMHO) Tapi itu benar-benar hanya pertanyaan gaya sebagai satu-satunya perbedaan aktual antara structdan classapakah yang satu default untuk pribadi dan yang lain untuk publik.
Gort the Robot

Jawaban:

13

Terkadang lebih tepat untuk menambahkan konstruktor ke struct dan kadang-kadang tidak.

Menambahkan konstruktor (konstruktor apa saja) ke struct mencegah penggunaan initializer agregat di atasnya. Jadi, jika Anda menambahkan konstruktor default, Anda juga harus mendefinisikan konstruktor non-default menginisialisasi nilai. Tetapi jika Anda ingin memastikan bahwa Anda selalu menginisialisasi semua anggota, itu tepat.

Menambahkan konstruktor (konstruktor apa saja, sekali lagi) membuatnya non-POD, tetapi dalam C ++ 11 sebagian besar aturan yang sebelumnya diterapkan ke POD hanya diubah untuk diterapkan ke objek tata letak standar dan menambahkan konstruktor tidak merusaknya. Jadi penginisialisasi agregat pada dasarnya adalah satu-satunya hal yang Anda kehilangan. Tetapi itu juga sering merupakan kerugian besar.

Jan Hudec
sumber
8

Dengan C ++ 11 bisa Anda lakukan

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

Dan setiap kali Anda lupa untuk menginisialisasi sesuatu, Anda mendapatkan inisialisasi default.

Vorac
sumber
-1

Jawaban cepat:

Itu tergantung pada apa yang ingin Anda capai.

Panjang, Diperpanjang, Jawaban Membosankan:

Anda memukul paku.

Saya biasanya tidak suka bahwa "C ++" memungkinkan "Struct (s)" memungkinkan untuk mendeklarasikan metode. Lebih disukai, saya menggunakan eksplisit "Kelas (es)" untuk metode yang diperlukan dan POD "Struct (s)" untuk bidang saja.

Namun, saya setuju bahwa beberapa operasi sederhana dasar, seperti:

  • tetapkan nilai awal ("konstruktor")
  • membuat salinan struktur ("copy constructor)
  • menetapkan nilai ke struktur yang ada ("operator penetapan overload")

Diperlukan, dan, dalam keadaan itu, metode untuk struktur, masuk akal.

Saran

Solusi potensial lainnya adalah dengan menggunakan struktur POD, tetapi, masih secara konseptual memperlakukan mereka sebagai kelas dan objek.

Bungkus deklarasi tersebut dalam namespace, dan, tambahkan fungsi global, untuk tindakan yang paling penting.

Deklarasi kode dapat serupa dengan ini:

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

Kode yang menerapkan solusi, bisa jadi seperti ini:

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

Pendekatan alternatif ini lebih baik ketika alokasi memori data yang besar diperlukan, atau berinteraksi dengan perpustakaan bersama tingkat rendah lainnya.

Pendekatan ini, dengan beberapa perubahan, diterapkan dalam Pengembangan Game.

Tambahan

Secara pribadi, saya mempertimbangkan ekstensi sintaksis untuk "C ++", atau bahkan, PL berbasis "C ++" baru yang memecahkan masalah ini:

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

Bersulang.

umlcat
sumber