เราควรเพิ่มนวกรรมิกไว้ใน structs หรือไม่?


14

เรามักจะใช้ c ++ structs เพื่อกำหนดโครงสร้างข้อมูลเมื่อเทียบกับคลาสซึ่งสามารถเป็นโมดูลที่สมบูรณ์พร้อมเมธอดสมาชิก ตอนนี้ลึกลงไปเรารู้ว่าพวกเขาทั้งสองเหมือนกัน (พูดอย่างหลวม ๆ )

ความจริงที่ว่าเรามักจะใช้ / รักษา structs เป็นข้อมูลหน่วยงานเท่านั้นสร้างความอยากนี้ที่เราไม่ได้เพิ่มตัวสร้างเริ่มต้นเช่นกัน แต่คอนสตรัคเตอร์นั้นยอดเยี่ยมอยู่เสมอพวกเขาทำให้สิ่งต่าง ๆ ง่ายขึ้นและช่วยกำจัดข้อผิดพลาด

มันจะขมวดคิ้วถ้าเพิ่มตัวสร้างเริ่มต้นให้กับโครงสร้างข้อมูลของฉัน?

การใช้Constructor ที่เป็นค่าเริ่มต้นยังทำให้โครงสร้าง Non-POD (ชนิดข้อมูลเก่าแบบเดิม) จัดทำตามเกณฑ์อื่น ๆ

เพื่อให้สิ่งต่าง ๆ ในมุมมองพิจารณาตัวอย่างง่าย ๆ แต่ในความเป็นจริง struct จะใหญ่กว่ามาก

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

ทุกครั้งที่ฉันสร้างวิธีการฉันต้องกังวลเกี่ยวกับ (พูดน้อยที่สุด) ถ้าฉันลืมตั้งค่าบางอย่าง ลองนึกภาพฉันลืมที่จะตั้งค่าtemperatureและใช้วิธีการกับระบบซึ่งตอนนี้เป็นค่าสูงแบบสุ่มและทำให้เกิดการทำร้ายร่างกาย หรือฉันลืมที่จะตั้งค่าdurationและตอนนี้วิธีการใช้ตัวเองสำหรับช่วงเวลาสูงที่ไม่รู้จัก

ทำไมฉันต้องรับผิดชอบในการเริ่มต้นวัตถุทุกครั้งแทนที่จะใช้ตัวสร้างซึ่งรับประกันได้หรือไม่


หากคุณจำเป็นต้องบังคับใช้ว่าอนุญาตเฉพาะค่าบางค่าคุณอาจไม่มีชนิดข้อมูลแบบเก่า หากคุณต้องการวิธีการเริ่มต้น struct ที่สะดวกฟังก์ชั่นเก่าธรรมดาจะทำเช่นนั้น
Doval

มันขึ้นอยู่กับสิ่งที่ตัวสร้างเหล่านี้กำลังทำอยู่ ฉันคิดว่ามันสมเหตุสมผลอย่างสมบูรณ์ที่จะมี Constructor ในโครงสร้างที่เรียบง่ายถ้ามันเป็นเพียงการตั้งค่าของฟิลด์ด้วยวิธีการพื้นฐาน
Gort the Robot

@Doval นั่นไม่ใช่คำถามฉันอัปเดตโพสต์ Steven: ใช่ตัวสร้างจะเพียงกำหนดค่าเริ่มต้นเท่านั้น
zadane

@StevenBurnap: หากตัวสร้างทำอะไรมากไปกว่าการตั้งค่าฟิลด์ด้วยวิธีการพื้นฐานมันก็จะเหมาะสมกว่าเท่านั้น แม้แต่ในโครงสร้าง
Jan Hudec

2
สิ่งที่ฉันหมายถึงคือถ้าคุณเริ่มหาตรรกะที่ซับซ้อนในตัวสร้างมันมีโอกาสที่คุณควรทำให้มันเป็นคลาส (IMHO) แต่จริงๆแล้วมันเป็นเพียงคำถามที่มีสไตล์เป็นความแตกต่างที่แท้จริงเพียงอย่างเดียวระหว่างstructและclassเป็นที่หนึ่งค่าเริ่มต้นให้เป็นส่วนตัวและอื่น ๆ เพื่อสาธารณะ
Gort the Robot

คำตอบ:


13

บางครั้งมันก็เหมาะสมที่จะเพิ่มนวกรรมิกให้กับ struct และบางครั้งก็ไม่เหมาะสม

การเพิ่มคอนสตรัคเตอร์ (คอนสตรัคใด ๆ ) ให้กับโครงสร้างการป้องกันโดยใช้ initializer รวมบนมัน ดังนั้นหากคุณเพิ่ม Constructor เริ่มต้นคุณจะต้องกำหนด Constructor ที่ไม่ใช่ค่าเริ่มต้นเพื่อกำหนดค่า แต่ถ้าคุณต้องการให้แน่ใจว่าคุณเริ่มต้นสมาชิกทุกคนมันก็เหมาะสม

การเพิ่มคอนสตรัคเตอร์ (คอนสตรัคใด ๆ อีกครั้ง) ทำให้ไม่ใช่ POD แต่ใน C ++ 11 กฎส่วนใหญ่ที่ใช้กับ POD ก่อนหน้านี้ถูกเปลี่ยนเพื่อใช้กับออบเจ็กต์เลย์เอาต์มาตรฐานเท่านั้น ดังนั้นการเริ่มต้นรวมเป็นเพียงสิ่งเดียวที่คุณสูญเสีย แต่มันก็มักจะสูญเสียครั้งใหญ่



-1

คำตอบที่รวดเร็ว:

มันขึ้นอยู่กับสิ่งที่คุณต้องการบรรลุ

ยาวขยายเพิ่มเติมคำตอบที่น่าเบื่อ:

คุณโดนเล็บ

ฉันมักจะไม่ชอบที่ "C ++" อนุญาตให้ "Struct (s)" อนุญาตให้ประกาศวิธีการ ฉันใช้ "Class (es)" อย่างชัดเจนสำหรับวิธีการที่จำเป็นและ POD "Struct (s)" สำหรับฟิลด์เท่านั้น

กระนั้นฉันยอมรับว่าการดำเนินการพื้นฐานบางอย่างง่าย ๆ เช่น:

  • กำหนดค่าเริ่มต้น ("ตัวสร้าง")
  • ทำสำเนาของโครงสร้าง ("ตัวสร้างสำเนา)
  • กำหนดค่าให้กับโครงสร้างที่มีอยู่ ("ตัวดำเนินการกำหนดภาระเกิน")

มีความจำเป็นและในกรณีเหล่านี้มีวิธีการในการสร้างโครงสร้างที่เหมาะสม

ข้อเสนอแนะ

วิธีแก้ปัญหาที่เป็นไปได้อีกอย่างหนึ่งคือการใช้โครงสร้าง 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

ไชโย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.