Chúng ta có nên thêm constructor vào structs?


13

Chúng ta thường sử dụng các cấu trúc c ++ để định nghĩa cấu trúc dữ liệu trái ngược với lớp có thể là một mô-đun hoàn chỉnh với các phương thức thành viên. Bây giờ sâu thẳm, chúng tôi biết cả hai đều giống nhau (nói một cách lỏng lẻo).

Thực tế là chúng ta thường sử dụng / xử lý các cấu trúc như các thực thể chỉ dữ liệu tạo ra sự thôi thúc này mà chúng ta cũng không thêm các hàm tạo mặc định. Nhưng các nhà xây dựng luôn tuyệt vời, họ làm cho mọi thứ đơn giản hơn và giúp loại bỏ lỗi.

Nó sẽ được nhăn mặt nếu thêm các hàm tạo mặc định vào cấu trúc dữ liệu của tôi?

Việc triển khai hàm tạo mặc định cũng làm cho cấu trúc Non-POD (kiểu dữ liệu cũ đơn giản) được cung cấp các tiêu chí khác được đáp ứng?

Để đặt mọi thứ trong quan điểm, hãy xem xét một ví dụ đơn giản nhưng trong thực tế, cấu trúc sẽ lớn hơn nhiều.

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

Mỗi lần tôi tạo một phương thức, tôi phải lo lắng (ít nhất là nói) nếu tôi quên đặt một số giá trị. Hãy tưởng tượng tôi quên thiết lập temperaturevà áp dụng phương pháp cho hệ thống mà bây giờ là một giá trị cao ngẫu nhiên và gây ra tình trạng hỗn loạn. Hoặc tôi quên cài đặt durationvà bây giờ phương thức này tự áp dụng trong một thời gian cao không xác định.

Tại sao tôi phải có trách nhiệm khởi tạo đối tượng mỗi lần thay vì triển khai hàm tạo của nó để đảm bảo nó?


Nếu bạn cần phải thực thi rằng chỉ cho phép một số giá trị nhất định, thì bạn hoàn toàn không có kiểu dữ liệu cũ đơn giản. Nếu bạn chỉ muốn các cách khởi tạo cấu trúc thuận tiện, các hàm cũ đơn giản sẽ làm điều đó.
Doval

Nó phụ thuộc vào những gì các nhà xây dựng đang làm. Tôi nghĩ rằng việc xây dựng một cấu trúc đơn giản là hoàn toàn hợp lý nếu nó chỉ thiết lập các giá trị trường theo những cách cơ bản.
Gort Robot

@Doval đó không phải là câu hỏi, tôi cập nhật bài viết. Steven: có, các nhà xây dựng sẽ chỉ được gán các giá trị mặc định.
zadane

@StevenBurnap: Nếu nhà xây dựng làm bất cứ điều gì hơn là chỉ thiết lập các giá trị trường theo những cách cơ bản thì chỉ có nó là phù hợp hơn . Ngay cả trên một cấu trúc.
Jan Hudec

2
Ý tôi là, nếu bạn bắt đầu tìm thấy logic phức tạp trong hàm tạo, có khả năng là bạn nên biến nó thành một lớp. (IMHO) Nhưng đó thực sự chỉ là một câu hỏi về phong cách vì sự khác biệt thực sự duy nhất giữa structclassđó là một mặc định là riêng tư và khác là công khai.
Gort Robot

Câu trả lời:


13

Đôi khi nó thích hợp để thêm constructor vào một cấu trúc và đôi khi không.

Thêm hàm tạo (bất kỳ hàm tạo nào) vào một cấu trúc sẽ ngăn việc sử dụng trình khởi tạo tổng hợp trên nó. Vì vậy, nếu bạn thêm một hàm tạo mặc định, bạn cũng sẽ phải xác định hàm tạo không mặc định khởi tạo các giá trị. Nhưng nếu bạn muốn đảm bảo rằng bạn luôn khởi tạo tất cả các thành viên, điều đó là phù hợp.

Thêm hàm tạo (bất kỳ hàm tạo nào, một lần nữa) làm cho nó không phải là POD, nhưng trong C ++ 11, hầu hết các quy tắc được áp dụng trước đây cho POD chỉ được thay đổi để áp dụng cho các đối tượng bố cục tiêu chuẩn và thêm các hàm tạo không phá vỡ điều đó. Vì vậy, trình khởi tạo tổng hợp về cơ bản là thứ duy nhất bạn mất. Nhưng nó cũng thường là một mất mát lớn.


8

Với C ++ 11 bạn có thể làm

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

Và bất cứ khi nào bạn quên khởi tạo một cái gì đó, bạn sẽ có được khởi tạo mặc định.


-1

Câu trả lời nhanh:

Nó phụ thuộc vào những gì bạn muốn đạt được.

Câu trả lời dài, mở rộng, nhàm chán:

Bạn đánh móng tay.

Tôi thường không thích rằng "C ++" cho phép "Struct (s)" cho phép khai báo các phương thức. Tốt hơn là, tôi sử dụng "Class (es)" rõ ràng cho các phương thức cần thiết và POD "Struct (s)" chỉ cho các trường.

Tuy nhiên, tôi đồng ý rằng một số thao tác đơn giản cơ bản, như:

  • gán giá trị ban đầu ("hàm tạo")
  • tạo một bản sao của cấu trúc ("copy constructor)
  • gán giá trị cho cấu trúc hiện có ("toán tử gán quá tải")

Được yêu cầu, và, trong những trường hợp đó, các phương pháp cho các cấu trúc, có ý nghĩa.

Gợi ý

Một giải pháp tiềm năng khác là sử dụng các cấu trúc POD, nhưng, về mặt khái niệm vẫn coi chúng là các lớp và các đối tượng.

Gói các khai báo đó trong một không gian tên và thêm các hàm toàn cục cho các hành động quan trọng nhất.

Khai báo mã có thể tương tự như sau:

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

Mã áp dụng giải pháp, có thể là một cái gì đó như thế này:

#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ách tiếp cận thay thế này tốt hơn khi cần phân bổ dữ liệu bộ nhớ lớn hoặc tương tác với các thư viện chia sẻ cấp thấp khác.

Cách tiếp cận này, với một số thay đổi, được áp dụng trong Phát triển trò chơi.

Thêm

Cá nhân, tôi xem xét một phần mở rộng cú pháp cho "C ++", hoặc thậm chí, một PL dựa trên "C ++" mới giải quyết vấn đề này:

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

Chúc mừng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.