เมื่อใดที่คุณควรใช้คลาส vs a struct ใน C ++


949

ในสถานการณ์ใดดีกว่าที่จะใช้structvs a classใน C ++


47
สิ่งนี้ไม่เพียงใช้กับ C ++ เท่านั้น แต่สำหรับภาษาใด ๆ ที่มีทั้ง structs และคลาส
เจสันตอม่อ

3
ฉันยังไม่เห็นด้วย - ฉันเข้าหาคำถามนี้แบบกึ่งความหมาย อาจมีความแตกต่างทางเทคนิคบางอย่าง แต่ความหมายพวกเขาไม่ได้ โครงสร้างมีประโยชน์จริงๆสำหรับการสร้างประเภทค่าคลาสไม่ได้
35490 Jason

4
ฉันเชื่อว่าไม่มีเหตุผลที่ร้ายแรงสำหรับการใช้ structs ใน C ++ ให้ฉัน structs เป็น "คุณสมบัติ" ซ้ำซ้อนของ C ++ ที่มีอยู่เฉพาะสำหรับความเข้ากันได้กับ C เช่น typedefs สิ่งเหล่านี้จะไม่มีอยู่หาก C ++ ไม่ได้รับการดูแลในขั้นต้นว่าเป็นส่วนขยายไปยัง C และได้รับการออกแบบตั้งแต่เริ่มต้นเช่น Java โดยทั่วไปแล้วฉันพบว่าสิ่งที่แปลกประหลาดที่สุดเกี่ยวกับ C ++ นั้นเกี่ยวกับความเข้ากันได้ของ C
Kostas

5
โครงสร้าง - สำหรับ POD (ข้อมูลเก่าธรรมดา) และการเข้าถึงของสมาชิกทั้งหมดเป็นแบบสาธารณะ คลาส - เมื่อคุณต้องการ encapsulation ที่ดีขึ้นและต้องการฟังก์ชันสมาชิกเพื่อทำงานกับสถานะของคลาส
Navaneeth KN

4
นี่เป็นความจริงโดยการประชุมเท่านั้น ไม่มีความแตกต่างนอกเหนือจากการห่อหุ้มเริ่มต้น
Dave Hillier

คำตอบ:


804

ความแตกต่างระหว่าง a classและ a structใน C ++ คือโครงสร้างที่มีpublicสมาชิกเริ่มต้นและฐานและคลาสมีprivateสมาชิกและฐานเริ่มต้น ทั้งการเรียนและ structs สามารถมีส่วนผสมของpublic, protectedและprivateสมาชิกสามารถใช้มรดกและสามารถมีฟังก์ชั่นสมาชิก

ฉันขอแนะนำให้ใช้ structs เป็นโครงสร้างข้อมูลแบบเก่าโดยไม่มีคุณสมบัติคล้ายคลาสและใช้คลาสเป็นโครงสร้างข้อมูลรวมที่มีprivateฟังก์ชันข้อมูลและสมาชิก


99
struct ที่ไม่มีโมดิฟายเออร์หรือเมธอดเรียกว่าโครงสร้าง POD ซึ่งมีอยู่เป็นอินเตอร์เฟสที่เข้ากันได้กับไลบรารี C เนื่องจากรับประกันได้ว่าจะถูกจัดวางราวกับว่าเป็นโครงสร้าง C นอกเหนือจากข้อยกเว้นหนึ่งข้อนี้ความแตกต่างเพียงอย่างเดียวคือตามที่ระบุไว้
workmad3

26
@ workmad3: ชื่อนี้ทำให้เข้าใจผิด แต่ 9/4 (C ++ 03) พูดว่า: "POD-struct เป็นคลาสรวมที่ไม่มีสมาชิกข้อมูลที่ไม่คงที่ประเภท non-POD-struct ไม่ใช่ POD-union (หรืออาเรย์ประเภทดังกล่าว) หรือการอ้างอิงและไม่มีตัวดำเนินการกำหนดสำเนาที่ผู้ใช้กำหนดและไม่มีตัวทำลายที่ผู้ใช้กำหนด " ไม่มีข้อ จำกัด ในการใช้คีย์คลาส "struct" และไม่มีข้อ จำกัด ในการใช้ "สาธารณะ" (ดู 8.5.1 / 1 สำหรับข้อกำหนดรวม) นี่ไม่ใช่ความแตกต่างระหว่าง "struct" และ "class"

5
การใช้ "รวม" ของคุณอาจเข้าใจผิดเนื่องจากคำจำกัดความของมาตรฐาน :)

3
ตามหนังสือ "หลักการและการปฏิบัติ" ของ Stroustrup: "structs ควรใช้เป็นหลักซึ่งสมาชิกสามารถรับค่าใด ๆ " (เช่นที่ไม่มีค่าคงที่ของคลาสที่มีความหมายสามารถกำหนดได้)
antibus

6
แน่นอนว่าคุณสามารถใช้คลาสได้เมื่อเชื่อมต่อกับ C ไม่มีความแตกต่างระหว่างคลาสและโครงสร้าง Structs เป็นคลาส; การเข้าถึงเริ่มต้นเท่านั้นที่พลิกจากส่วนตัวเป็นสาธารณะ
เซบาสเตียนมัค

229

ในฐานะที่เป็นคนอื่น ๆ มีความแตกต่างจริงสองภาษาจริง:

  • structค่าเริ่มต้นในการเข้าถึงสาธารณะและclassค่าเริ่มต้นในการเข้าถึงแบบส่วนตัว
  • เมื่อสืบทอดให้ใช้structค่าเริ่มต้นเป็นpublicมรดกและclassค่าเริ่มต้นเป็นprivateมรดก (กระแทกแดกดันเช่นเดียวกับหลายสิ่งหลายอย่างใน C ++ ค่าเริ่มต้นคือย้อนกลับ: การpublicสืบทอดเป็นตัวเลือกที่ใช้กันทั่วไปมากกว่า แต่ผู้คนไม่ค่อยประกาศstructเพียงเพื่อประหยัดการพิมพ์publicคำหลัก ""

แต่ความแตกต่างที่แท้จริงในทางปฏิบัติคือระหว่างclass/ structที่ประกาศตัวสร้าง / destructor และที่ไม่ได้ มีการรับประกันบางอย่างสำหรับประเภท POD "ข้อมูลเก่าแก่" ซึ่งจะไม่มีผลบังคับใช้อีกต่อไปเมื่อคุณรับช่วงก่อสร้างของชั้นเรียน เพื่อให้ความแตกต่างนี้ชัดเจนคนจำนวนมากจงใจใช้เฉพาะstructสำหรับประเภท POD เท่านั้นและหากพวกเขาจะเพิ่มวิธีการใด ๆ ก็ตามให้ใช้classเอส ความแตกต่างระหว่างสองแฟรกเมนต์ด้านล่างนั้นไม่มีความหมาย:

class X
{
  public:

  // ...
};

struct X
{
  // ...
};

(อนึ่งนี่คือเธรดที่มีคำอธิบายที่ดีเกี่ยวกับความหมายของ "ประเภท POD" ที่แท้จริง: ประเภท POD ใน C ++ คืออะไร )


ตัวอย่างที่ดีเกี่ยวกับความแตกต่างของมรดก: ที่นี่
Liran Orevi

8
ไม่ว่าคุณจะใช้structหรือclassไม่มีการแบกว่าวัตถุของคุณเป็น POD หรือไม่คุณควรกำหนดตัวสร้างสำเนา / destructor ฟังก์ชั่นสมาชิกยังไม่มีผลต่อสิ่งที่เป็น POD ในขณะที่ฉันอ่านสิ่งที่คุณเขียนฉันเห็นว่าคุณไม่ได้แนะนำเป็นอย่างอื่น แต่ถ้อยคำปัจจุบันสับสน
เดวิดสโตน

1
@DavidStone โดยพื้นฐานแล้วโครงสร้าง POD ควรได้รับการรับประกันว่าเข้ากันได้กับโค้ด C และดังนั้นโดยพื้นฐานแล้วควรได้รับการออกแบบเป็นโครงสร้าง C-style
Justin Time - Reinstate Monica

3
ส่วน "ความแตกต่างที่แท้จริง" ของคำตอบนี้ผิดทั้งหมด
juanchopanza

177

มีความเข้าใจผิดมากมายในคำตอบที่มีอยู่

ทั้งสองclassและstructประกาศชั้นเรียน

ใช่คุณอาจต้องจัดเรียงคำสำคัญการปรับเปลี่ยนการเข้าถึงของคุณใหม่ภายในคำจำกัดความของคลาสขึ้นอยู่กับคำหลักที่คุณใช้ในการประกาศคลาส

แต่นอกเหนือจากวากยสัมพันธ์เหตุผลเดียวที่เลือกได้มากกว่าอีกข้อคือการประชุม / สไตล์ / การตั้งค่า

บางคนชอบที่จะยึดstructคำหลักสำหรับคลาสที่ไม่มีฟังก์ชั่นสมาชิกเนื่องจากคำนิยามผลลัพธ์ "ดูเหมือนว่า" โครงสร้างที่เรียบง่ายจาก C

ในทำนองเดียวกันบางคนชอบที่จะใช้classคำหลักสำหรับชั้นเรียนที่มีฟังก์ชั่นสมาชิกและprivateข้อมูลเพราะมันบอกว่า "ระดับ" ในนั้นและดูเหมือนว่าตัวอย่างจากหนังสือเล่มโปรดของพวกเขาในการเขียนโปรแกรมเชิงวัตถุ

ความจริงก็คือสิ่งนี้ขึ้นอยู่กับคุณและทีมของคุณอย่างสมบูรณ์และมันจะไม่ทำให้โปรแกรมของคุณแตกต่างอย่างแท้จริง

สองคลาสต่อไปนี้มีความเท่าเทียมกันทุกประการยกเว้นชื่อ:

struct Foo
{
   int x;
};

class Bar
{
public:
   int x;
};

คุณสามารถเปลี่ยนคำค้นหาเมื่อทำการประกาศใหม่:

class Foo;
struct Bar;

(แม้ว่าสิ่งนี้จะทำให้ Visual Studio สร้างขึ้นเนื่องจากความไม่สอดคล้องกันดังนั้นคอมไพเลอร์จะส่งเสียงเตือนเมื่อคุณทำเช่นนี้)

และนิพจน์ต่อไปนี้ทั้งคู่ประเมินว่าเป็นจริง:

std::is_class<Foo>::value
std::is_class<Bar>::value

ทำบันทึกได้ว่าคุณไม่สามารถเปลี่ยนคำหลักเมื่อกําหนด ; นี้เป็นเพียงเพราะ (ต่อกฎหนึ่งนิยาม) นิยามคลาสที่ซ้ำกันในหน่วยการแปลต้อง"ประกอบด้วยลำดับเดียวกันของสัญญาณ" ซึ่งหมายความว่าคุณไม่สามารถได้แลกเปลี่ยนconst int member;ด้วยint const member;และมีอะไรจะทำอย่างไรกับความหมายของหรือclassstruct


15
นี่เป็นข้อมูลที่มากและเป็นคำตอบที่ฉันโปรดปรานอย่างจริงใจ ทุกคนกำลังปฏิบัติต่อพวกเขาเป็นหน่วยงานที่แยกต่างหากเมื่ออยู่ใต้ฝากระโปรงพวกเขาเหมือนกัน ฉันสงสัยว่าความหมายของคำว่า struct ในสภาพแวดล้อม Arduino นั้นถือว่าเป็นคลาส cpp หรือไม่เพราะมันถูกคอมไพล์ด้วย g ++
เบนจามิน

4
@ แน่นอนมันเป็น คอมไพเลอร์ Arduino รวบรวม C ++; นั่นคือจุดสิ้นสุดของมัน
underscore_d

6
ดังนั้นหากฉันเข้าใจในสิ่งนี้: ตราบใดที่ตัวดัดแปลงการมองเห็นของคุณชัดเจนไม่ถูกมองข้ามก็ไม่เป็นไร คุณสามารถเขียนแอปพลิเคชั่น C ++ ขนาดใหญ่โดยไม่ต้องใช้อะไรนอกจาก structs; หรือคุณสามารถผ่านและเปลี่ยน struct ทุกกรณีเป็นคลาส ตราบใดที่คุณไม่ได้ใช้การเปิดเผยค่าเริ่มต้นแอปพลิเคชันจะเหมือนกันอย่างแม่นยำ
Ryan Lundy

ฉันไม่มั่นใจว่าหน่วยการแปลหนึ่งของโปรแกรม C ++ สามารถมีการประกาศอย่างสมบูรณ์class foo { public: ... };และอีกหน่วยหนึ่งสามารถมีได้struct foo { ... };ซึ่งจะต้องถือเป็นจริงตามการอ้างสิทธิ์ "เทียบเท่าอย่างแน่นอน" มันมาถึงเหตุผลที่ประกาศไม่สมบูรณ์struct foo;และclass foo;สามารถใช้แทนกันได้ สิ่งเหล่านี้ไม่ได้ระบุเนื้อหาของคลาสดังนั้นพวกเขาจึงไม่พูดอะไรกับโครงร่างการเข้าถึง
Kaz

@Kaz: ถูกต้อง - หากคำจำกัดความเป็นประเภทเดียวกันอย่างแท้จริงพวกเขาจะต้องเหมือนกันโดยคำศัพท์สำหรับพฤติกรรมที่จะกำหนดไว้อย่างดี struct ที่สำคัญและระดับที่สำคัญเป็นอย่างอื่นมีเหตุผลแลกเปลี่ยนแม้ว่า (ที่หมายจะไม่ได้รับผลกระทบ) และFooและBarยังคงเทียบเท่า / ประเภทเหมือนกัน ฉันแน่ใจว่าจะพูดว่า "เมื่อประกาศใหม่ " และยกตัวอย่าง ลองคิดดูสิฉันจะอธิบายเรื่องนี้ในคำตอบเพื่อให้แน่ใจว่าฉันไม่ได้ทำให้ผู้คนเข้าใจผิดใน UB
Lightness Races in Orbit

54

ครั้งเดียวที่ฉันใช้ struct แทนคลาสคือเมื่อประกาศ functor ก่อนที่จะใช้ในการเรียกใช้ฟังก์ชั่นและต้องการลดไวยากรณ์ให้น้อยที่สุดเพื่อความชัดเจน เช่น:

struct Compare { bool operator() { ... } };
std::sort(collection.begin(), collection.end(), Compare()); 

35
ตอนนี้มันเป็นเวลาหลายปีต่อมาและ C ++ 11 ได้รับการสนับสนุนโดยทุกคอมไพเลอร์ที่สำคัญLambdas ทำเรื่องนี้ให้รัดกุมมากยิ่งขึ้น

36

จากC ++ FAQ Lite :

สมาชิกและคลาสพื้นฐานของโครงสร้างเป็นสาธารณะโดยค่าเริ่มต้นในขณะที่อยู่ในชั้นเรียนพวกเขาเริ่มต้นเป็นส่วนตัว หมายเหตุ: คุณควรทำให้คลาสพื้นฐานของคุณเป็นสาธารณะส่วนตัวหรือได้รับการป้องกันอย่างชัดเจนแทนที่จะต้องพึ่งพาค่าเริ่มต้น

struct และคลาสนั้นมีหน้าที่เทียบเท่ากัน

ตกลงพอพูดคุยเทคโนสะอาดที่สะอาดสะอ้าน นักพัฒนาส่วนใหญ่สร้างความแตกต่างอย่างชัดเจนระหว่างคลาสและโครงสร้าง struct เพียงแค่รู้สึกเหมือนกองเปิดที่มีบิตน้อยมากในทางของการห่อหุ้มหรือการทำงาน ชั้นรู้สึกเป็นสมาชิกที่อยู่อาศัยและมีความรับผิดชอบของสังคมด้วยบริการที่ชาญฉลาดอุปสรรคการห่อหุ้มที่แข็งแกร่งและอินเตอร์เฟซที่กำหนดไว้อย่างดี เนื่องจากเป็นความหมายแฝงที่คนส่วนใหญ่มีอยู่แล้วคุณควรใช้คำสำคัญ struct หากคุณมีคลาสที่มีวิธีการน้อยมากและมีข้อมูลสาธารณะ (สิ่งต่าง ๆ มีอยู่ในระบบที่ออกแบบมาอย่างดี!) แต่อย่างอื่นคุณควรใช้คลาส คำสำคัญ.


1
ผมไม่เข้าใจว่าทำไมพวกเขาจะระบุว่า struct และชั้นมีหน้าที่เหมือนกัน แต่บอกว่าจะชอบหนึ่งในช่วงอื่น ๆ ในบางกรณีโดยไม่มีเหตุผลใด ๆ ..
Deetz

3
เหตุผลก็คือการประชุม คอมไพเลอร์ไม่สนใจสิ่งที่คุณใช้ แต่นักพัฒนาคนอื่นมองที่รหัสของคุณจะมีเวลาเข้าใจง่ายขึ้นว่าคุณหมายถึงอะไร
Tal Pressman

3
@deetz: ย่อหน้าที่สามทั้งหมดมีเหตุผล
Lightness Races ในวงโคจร

ว้าวมาจาก 'โรงเรียนเก่า' ฉันไม่รู้ว่าโครงสร้างอาจมีวิธีการและการสืบทอดได้ ฉันมักจะใช้ struct สำหรับเมื่อใช้เพียงข้อมูลเท่านั้นโดยไม่มีวิธีการและมักจะเมื่อจัดการกับรหัส API ที่ต้องการโครงสร้าง structs สามารถรองรับการสืบทอดหลายอย่างได้หรือไม่
Paul McCarthy

21

ที่เดียวที่ struct มีประโยชน์สำหรับฉันคือเมื่อฉันมีระบบที่ได้รับข้อความจัดรูปแบบคงที่ (over say, serial port) จากระบบอื่น คุณสามารถส่งกระแสข้อมูลไบต์ลงในโครงสร้างที่กำหนดเขตข้อมูลของคุณและเข้าถึงเขตข้อมูลได้อย่างง่ายดาย

typedef struct
{
    int messageId;
    int messageCounter;
    int messageData;
} tMessageType;

void processMessage(unsigned char *rawMessage)
{
    tMessageType *messageFields = (tMessageType *)rawMessage;
    printf("MessageId is %d\n", messageFields->messageId);
}

เห็นได้ชัดว่านี่คือสิ่งเดียวกับที่คุณจะทำใน C แต่ฉันพบว่าค่าใช้จ่ายในการถอดรหัสข้อความในชั้นเรียนมักจะไม่คุ้มค่า


สามารถทำได้เหมือนกันใน C.
Eugene Bujak

11
หรือคุณสามารถนำไปใช้operator >>กับคลาสแทนการเขียนprocessMessageฟังก์ชั่นซึ่งจะทำให้ C ++ ของคุณดูเหมือน C ++ ที่เหมาะสมกว่าและน้อยกว่าเช่น C
Nick Bastin

1
นอกเหนือจากความจริงที่ว่ามันไม่สามารถพกพาได้ระหว่างระบบที่แตกต่างกันนี้เป็นการละเมิดกฎนามแฝงดังนั้นจึงไม่รับประกันว่าจะทำงานได้แม้ในสถาปัตยกรรมเดียว
underscore_d

@underscore_d สิ่งนี้สามารถทำงานได้บนแพลตฟอร์ม (แต่ไม่ใช่คอมไพเลอร์) แต่คุณต้องใช้ bitfields แบบคงที่__packed__struct และมีการใช้งาน ifdef ifdef แบบ endian-aware (คุณต้องพลิกลำดับบนเครื่องที่ endianess อยู่ตรงข้ามกับแหล่งข้อมูลภายนอก กำลังจัดหาบริการ) มันไม่สวย แต่ฉันเคยแพ็ค / เอาออกลงทะเบียนสำหรับอุปกรณ์ต่อพ่วงระยะไกลบนแพลตฟอร์มแบบฝังในแบบพกพา
crasic

1
@jacwah Huh จุดดี การใช้นามแฝงจะไม่มีปัญหาที่นี่เนื่องจากพอยน์เตอร์ตัวใดตัวหนึ่งเป็นcharประเภทซึ่งได้รับการยกเว้นจากการใช้นามแฝง อย่างไรก็ตามยังคงมีปัญหาแม้ว่าจะแตกต่างกัน: การส่งchar*ไปยังประเภทที่แตกต่างกันหากไม่มีวัตถุใด ๆ ของประเภทหลังที่เริ่มต้นแล้วที่ที่อยู่นั้นเป็น UB เนื่องจากละเมิดกฎอายุการใช้งาน ตอนนี้, แม้ว่าประเภทปลายทางนั้นสามารถสร้างได้เพียงเล็กน้อย, เพียงแค่มีหน่วยความจำที่จัดสรรไม่เพียงพอสำหรับ C ++ ที่จะอนุญาตให้รักษาหน่วยความจำนั้นเป็นประเภทนั้นได้อย่างเป็นทางการ
underscore_d

19

คุณสามารถใช้ "struct" ใน C ++ หากคุณกำลังเขียนไลบรารีที่มี internals เป็น C ++ แต่ API สามารถเรียกได้ด้วยรหัส C หรือ C ++ คุณเพียงแค่สร้างส่วนหัวเดียวที่มีฟังก์ชั่น structs และ API ระดับโลกที่คุณเปิดเผยให้ทั้งรหัส C และ C ++ ดังนี้:

// C access Header to a C++ library
#ifdef __cpp
extern "C" {
#endif

// Put your C struct's here
struct foo
{
    ...
};
// NOTE: the typedef is used because C does not automatically generate
// a typedef with the same name as a struct like C++.
typedef struct foo foo;

// Put your C API functions here
void bar(foo *fun);

#ifdef __cpp
}
#endif

จากนั้นคุณสามารถเขียนแถบฟังก์ชั่น () ในไฟล์ C ++ โดยใช้รหัส C ++ และทำให้สามารถเรียกใช้ได้จาก C และทั้งสองโลกสามารถแบ่งปันข้อมูลผ่านทาง struct ที่ประกาศไว้ แน่นอนมีข้อแม้อื่น ๆ เมื่อผสม C และ C ++ แต่นี่เป็นตัวอย่างที่ง่าย


2
คำตอบที่เหมาะสมที่สุด ความเข้ากันได้กับ C เป็นเหตุผลที่สำคัญที่สุด สิ่งอื่น ๆ ทั้งหมดเช่นการเข้าถึงเริ่มต้นเป็นความลับ
Valentin Heinitz

16

ตามที่ทุกคนพูดความแตกต่างที่แท้จริงเพียงอย่างเดียวคือการเข้าถึงเริ่มต้น แต่โดยเฉพาะอย่างยิ่งฉันใช้ struct เมื่อฉันไม่ต้องการการห่อหุ้มใด ๆ กับคลาสข้อมูลอย่างง่ายแม้ว่าฉันจะใช้วิธีการช่วยเหลือบางอย่าง ตัวอย่างเช่นเมื่อฉันต้องการอะไรแบบนี้

struct myvec {
    int x;
    int y;
    int z;

    int length() {return x+y+z;}
};

1
+1 สำหรับยกตัวอย่างของ struct ที่มีฟังก์ชั่นสมาชิกบางตัวที่ไม่รู้สึกว่าคุณได้ "ทำลายโครงสร้าง" ไปแล้ว
einpoklum

9

เพื่อตอบคำถามของฉันเอง (ไร้ยางอาย) ดังที่ได้กล่าวไปแล้วสิทธิ์การเข้าถึงนั้นแตกต่างกันระหว่าง C ++ เท่านั้น

ฉันมักจะใช้ struct สำหรับเก็บข้อมูลเท่านั้น ฉันจะอนุญาตให้ใช้ฟังก์ชันตัวช่วยสองสามอย่างถ้ามันทำให้การทำงานกับข้อมูลง่ายขึ้น อย่างไรก็ตามทันทีที่ข้อมูลต้องการการควบคุมการไหล (เช่นตัวรับ / ตัวตั้งค่าที่รักษาหรือปกป้องสถานะภายใน) หรือเริ่มรับฟังก์ชั่นที่สำคัญใด ๆ (โดยทั่วไปคล้ายกับวัตถุมากขึ้น) มันจะได้รับ


9

Structs ( PODs , โดยทั่วไป) มีประโยชน์เมื่อคุณมีอินเตอร์เฟสที่ใช้งานร่วมกับ C ได้ซึ่งมีการติดตั้ง C ++ เนื่องจากพวกมันพกพาข้ามพรมแดนภาษาและรูปแบบลิงเกอร์

หากนั่นไม่ใช่ข้อกังวลของคุณฉันคิดว่าการใช้ "struct" แทน "class" เป็นผู้สื่อสารที่ตั้งใจดี (ดังที่ @ ZeroSignal กล่าวไว้ด้านบน) โครงสร้างยังมีซีแมนทิกส์การคัดลอกที่คาดเดาได้มากขึ้นดังนั้นมันจึงมีประโยชน์สำหรับข้อมูลที่คุณตั้งใจจะเขียนไปยังสื่อภายนอกหรือส่งข้ามสาย

Structs ยังมีประโยชน์สำหรับงาน metaprogramming ต่างๆเช่นเทมเพลตคุณลักษณะที่เพิ่งพิมพ์กลุ่มของการพิมพ์ที่ขึ้นอยู่กับ:

template <typename T> struct type_traits {
  typedef T type;
  typedef T::iterator_type iterator_type;
  ...
};

... แต่นั่นเป็นเพียงการใช้ประโยชน์จากระดับการป้องกันเริ่มต้นของ struct เป็นสาธารณะ ...


1
นั่นไม่ใช่การใช้งาน POD ที่ถูกต้อง struct (หรือคลาส) สามารถเป็นโครงสร้าง POD หาก (และเฉพาะในกรณีที่) มีสมาชิก POD เท่านั้น
Martin York

4
"ซีแมนทิกส์การคัดลอกที่คาดเดาได้": ไซแมนทิกส์เหมือนกับคลาส (และมีปัญหาเดียวกัน (สำเนาตื้น))
Martin York

2
โพสต์นี้จะทำให้คุณเชื่อ (หวังว่าโดยบังเอิญ) ว่า structs ทั้งหมดเป็น POD นี่ไม่เป็นความจริงเลย ฉันหวังว่าผู้คนจะไม่เข้าใจผิดโดยสิ่งนี้
Michael Dorst

8

สำหรับ C ++ มีความแตกต่างระหว่าง structs และคลาสไม่มาก ความแตกต่างการทำงานหลักคือสมาชิกของ struct เป็นสาธารณะโดยค่าเริ่มต้นในขณะที่พวกเขาเป็นส่วนตัวโดยค่าเริ่มต้นในชั้นเรียน มิฉะนั้นเท่าที่ภาษาเกี่ยวข้องพวกเขาจะเทียบเท่า

ที่กล่าวว่าฉันมักจะใช้ structs ใน C ++ เหมือนที่ฉันทำใน C # เหมือนกับที่ Brian พูด Structs เป็นที่เก็บข้อมูลแบบง่าย ๆ ในขณะที่คลาสใช้สำหรับวัตถุที่ต้องดำเนินการกับข้อมูลนอกเหนือไปจากเพียงแค่เก็บไว้กับมัน


4

พวกมันค่อนข้างเหมือนกัน ด้วยความมหัศจรรย์ของ C ++ ทำให้โครงสร้างสามารถเก็บฟังก์ชันใช้การสืบทอดสร้างโดยใช้ "ใหม่" และอื่น ๆ เช่นเดียวกับคลาส

ความแตกต่างด้านการใช้งานเพียงอย่างเดียวคือคลาสเริ่มต้นด้วยสิทธิ์การเข้าถึงส่วนตัวในขณะที่โครงสร้างเริ่มต้นด้วยสาธารณะ นี่คือการรักษาความเข้ากันได้ย้อนหลังกับ C.

ในทางปฏิบัติฉันมักจะใช้ structs เป็นผู้ถือข้อมูลและคลาสเป็นวัตถุ


4

ตามที่คนอื่น ๆ ได้ชี้ให้เห็น

  • ทั้งสองมีความเท่าเทียมกันนอกเหนือจากการมองเห็นเริ่มต้น
  • อาจมีเหตุผลที่จะถูกบังคับให้ใช้อย่างใดอย่างหนึ่งด้วยเหตุผลใดก็ตาม

มีคำแนะนำที่ชัดเจนเกี่ยวกับเวลาที่ใช้จาก Stroustrup / Sutter:

ใช้คลาสถ้าคลาสมีค่าคงที่ ใช้ struct ถ้าสมาชิกข้อมูลสามารถแตกต่างกันอย่างอิสระ

อย่างไรก็ตามโปรดทราบว่าไม่ควรส่งต่อ sth เป็นคลาส ( class X;) และกำหนดเป็น struct ( struct X { ... }) มันอาจทำงานกับลิงเกอร์บางตัว (เช่น g ++) และอาจล้มเหลวกับลิงค์อื่น ๆ (เช่น MSVC) ดังนั้นคุณจะพบว่าตัวเองอยู่ในนรกนักพัฒนา


คุณสามารถอธิบายปัญหาตัวเชื่อมโยงเหล่านี้ได้หรือไม่?
การแข่งขัน Lightness ใน Orbit

@LightnessRacesinOrbit ฉันทำไม่ได้โชคไม่ดี ฉันไม่สามารถสร้างตัวอย่างได้ จิ๊บจ๊อยclass Foo; struct Foo { void bar() {} }; int main() { Foo().bar(); }ไม่เพียง แต่คอมไพล์และทำงานกับ MSVC ปี 2017 มันก็ก่อให้เกิดคำเตือนที่ชัดเจนว่าFooได้รับการประกาศให้เป็นแต่กำหนดให้เป็นstruct classแต่ฉันยังจำได้อย่างชัดเจนว่ามันมีค่าใช้จ่ายทีมของเราครึ่งวันเพื่อหาข้อผิดพลาดที่โง่ ฉันไม่แน่ใจว่าเราใช้ MSVC รุ่นใดในตอนนั้น
pasbi

ตัวเชื่อมโยงไม่ควรรู้ด้วยซ้ำว่าคุณใช้classหรือstructประกาศไปข้างหน้าและทั้งสองสามารถใช้แทนกันได้อย่างอิสระตามมาตรฐาน (แม้ว่าจะรู้ว่า VS เตือนฉันมักจะสันนิษฐานว่าเป็นเพียงเพื่อหลีกเลี่ยงความผิดพลาดของโปรแกรมเมอร์ที่ชัดเจน) มีบางอย่างไม่ได้อยู่ที่นี่ คุณแน่ใจหรือว่าไม่ใช่ข้อผิดพลาดการละเมิด ODR
การแข่งขัน Lightness ใน Orbit


ฉันจำไม่ได้แน่นอน ปัญหาไม่ได้เกิดขึ้นในแอปพลิเคชันโดยตรง แต่ในไลบรารีที่ใช้ใน gtest ฉันเพิ่งรู้ว่าตัวเชื่อมโยงสร้างข้อผิดพลาดที่เข้าใจไม่ได้ (LNK ???) เมื่อฉันแทนที่ - structไปclassข้างหน้าเป็น - ข้างหน้าปัญหาก็หายไป ณ วันนี้ฉันพบว่ามันแปลกด้วย ฉันจะดีใจถ้าคุณสามารถทำให้ไฟบางอย่าง
pasbi

3

ชั้น

สมาชิกของคลาสจะเป็นส่วนตัวโดยค่าเริ่มต้น

class test_one {
    int main_one();
};

มีค่าเท่ากับ

class test_one {
  private:
    int main_one();
};

ดังนั้นหากคุณลอง

int two = one.main_one();

เราจะได้รับข้อผิดพลาด: main_one is privateเพราะมันไม่สามารถเข้าถึงได้ เราสามารถแก้ปัญหาได้โดยเริ่มต้นด้วยการระบุสาธารณะเช่น

class test_one {
  public:
    int main_one();
};

โครงสร้าง

struct คือคลาสที่สมาชิกเป็นแบบสาธารณะโดยค่าเริ่มต้น

struct test_one {
    int main_one;
};

หมายถึงmain_oneเป็นส่วนตัวเช่น

class test_one {
  public:
    int main_one;
};

ฉันใช้ structs สำหรับโครงสร้างข้อมูลที่สมาชิกสามารถรับค่าใด ๆ ได้ง่ายกว่านั้น


3

ข้อได้เปรียบของstructover classคือการบันทึกรหัสหนึ่งบรรทัดหากยึดมั่นใน "สมาชิกสาธารณะคนแรกแล้วส่วนตัว" ในแง่นี้ฉันพบว่าคำหลักclassไร้ประโยชน์

นี่คือเหตุผลในการใช้เพียงอีกและไม่เคยstruct classหลักเกณฑ์สไตล์รหัสบางอย่างสำหรับ C ++ แนะนำให้ใช้ตัวอักษรขนาดเล็กสำหรับฟังก์ชันแมโครเหตุผลที่ว่าเมื่อแมโครถูกแปลงเป็นฟังก์ชันแบบอินไลน์ชื่อไม่ควรมีการเปลี่ยนแปลง กันที่นี่ คุณมีโครงสร้างแบบ C ที่ดีและวันหนึ่งคุณพบว่าคุณต้องเพิ่มตัวสร้างหรือวิธีการอำนวยความสะดวกบางอย่าง คุณเปลี่ยนเป็น a classหรือไม่? ทุกที่?

การแยกแยะความแตกต่างระหว่างstructs classกับ es นั้นยุ่งยากมากเกินไปการเข้าไปทำสิ่งที่เราควรจะทำ - การเขียนโปรแกรม เช่นเดียวกับปัญหาหลายอย่างของ C ++ มันเกิดขึ้นจากความปรารถนาอย่างแรงกล้าในการใช้งานร่วมกันได้


ทำไมคุณต้องเปลี่ยนเป็น a class? คุณคิดว่าคลาสที่กำหนดด้วยstructคำหลักไม่สามารถมีฟังก์ชันสมาชิกหรือตัวสร้างได้
Lightness Races ในวงโคจร

@LightnessRacesinOrbit เนื่องจาก 1. ความสอดคล้องและ 2. นักวิเคราะห์แบบคงที่บางคนบ่นเกี่ยวกับการละเมิด 1.
Vorac

ที่ไม่ปฏิบัติตาม "ความสอดคล้อง" อื่นใดที่คุณยึดถือ? ทุกคลาสที่มีสมาชิกที่เรียกjoe()จะต้องกำหนดด้วยclassคำหลัก? ทุกคลาสที่มีintสมาชิกอย่างน้อย 4 คนจะต้องกำหนดด้วยstructคำหลัก?
Lightness Races ในวงโคจร

@LightnessRacesinOrbit ฉันหมายถึงสำนวน "มวลรวม POD ถูกกำหนดด้วยstructมวลรวมกับวิธีการที่ถูกกำหนดด้วยclass" ยุ่งยากมากเกินไป
Vorac

2

มันเป็นสิ่งเดียวกันกับค่าเริ่มต้นที่แตกต่างกัน (ส่วนตัวโดยค่าเริ่มต้นสำหรับclassและสาธารณะโดยค่าเริ่มต้นสำหรับstruct) ดังนั้นในทางทฤษฎีพวกเขาสามารถใช้แทนกันได้อย่างสมบูรณ์

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


2

โครงสร้างโดยค่าเริ่มต้นมีการเข้าถึงสาธารณะและคลาสโดยค่าเริ่มต้นมีการเข้าถึงแบบส่วนตัว

ส่วนตัวผมใช้ structs สำหรับ Data Transfer Objects หรือ Value Objects เมื่อใช้ฉันจะประกาศสมาชิกทั้งหมดว่าเป็น const เพื่อป้องกันการแก้ไขด้วยรหัสอื่น


2

ทั้งสองstructและclassเหมือนกันภายใต้ประทุนแม้ว่าจะมีค่าเริ่มต้นแตกต่างกันไปสำหรับการมองเห็นstructค่าเริ่มต้นคือสาธารณะและclassค่าเริ่มต้นเป็นแบบส่วนตัว คุณสามารถเปลี่ยนคนใดคนหนึ่งจะเป็นอื่น ๆ ที่มีการใช้งานที่เหมาะสมและprivate publicพวกเขาทั้งสองอนุญาตให้สืบทอดวิธีการก่อสร้างคอนสตรัคเตอร์และส่วนที่เหลือทั้งหมดของสินค้าของภาษาเชิงวัตถุ

อย่างไรก็ตามสิ่งที่แตกต่างกันอย่างมากระหว่างสองคือว่าstructเป็นคำหลักที่ได้รับการสนับสนุนใน C ในขณะที่classไม่ได้ ซึ่งหมายความว่าสามารถใช้structในรวมไฟล์ที่สามารถ#includeเข้าไปในทั้ง C ++ หรือ C ตราบเท่าที่structเป็นรูปแบบธรรมดา C structและทุกสิ่งทุกอย่างในแฟ้มรวมเข้ากันได้กับ C คือไม่มี c ++ คำหลักที่เฉพาะเจาะจงเช่นprivate, publicไม่มี วิธีการไม่มีมรดก ฯลฯ ฯลฯ ฯลฯ

AC style structสามารถใช้กับอินเตอร์เฟสอื่น ๆ ที่รองรับการใช้ C style structเพื่อนำข้อมูลไปมาผ่านทางอินเตอร์เฟส

AC style structเป็นเทมเพลตชนิดหนึ่ง (ไม่ใช่เท็มเพลต C ++ แต่เป็นรูปแบบหรือ stencil) ที่อธิบายโครงร่างของพื้นที่หน่วยความจำ กว่าปีที่อินเตอร์เฟซที่ใช้งานได้จาก C และ C ปลั๊กอิน (ที่นี่ที่มองหาที่คุณ Java และ Python และ Visual Basic) structได้รับการสร้างบางส่วนของที่ทำงานที่มีสไตล์


1

ในทางเทคนิคทั้งสองจะเหมือนกันใน C ++ - ตัวอย่างเช่นเป็นไปได้ที่ struct จะมีตัวดำเนินการมากเกินไปเป็นต้น

อย่างไรก็ตาม:

ฉันใช้ structs เมื่อฉันต้องการส่งผ่านข้อมูลหลายประเภทพร้อมกันฉันใช้คลาสเมื่อฉันจัดการกับวัตถุ "ใช้งานได้"

หวังว่ามันจะช่วย

#include <string>
#include <map>
using namespace std;

struct student
{
    int age;
    string name;
    map<string, int> grades
};

class ClassRoom
{
    typedef map<string, student> student_map;
  public :
    student getStudentByName(string name) const 
    { student_map::const_iterator m_it = students.find(name); return m_it->second; }
  private :
    student_map students;
};

ตัวอย่างเช่นฉันกลับนักเรียน struct ในการรับ ...


1

คุณจะเลือกใช้ struct เมื่อใดและควรใช้คลาสใดใน C ++

ผมใช้structเมื่อฉันกำหนดและfunctors มิฉะนั้นการใช้งานผมPODclass

// '()' is public by default!
struct mycompare : public std::binary_function<int, int, bool>
{
    bool operator()(int first, int second)
    { return first < second; }
};

class mycompare : public std::binary_function<int, int, bool>
{
public:
    bool operator()(int first, int second)
    { return first < second; }
};

1
คำตอบนี้แสดงสัญญาณอายุ :) std::binary_function<>ไม่ได้คัดค้านเพียงแค่ c ++ 17 ยังสามารถลบออกได้
sehe

ไม่แปลกใจจริง ๆ เพราะมันถูกเขียนขึ้นในช่วงเวลาของ C ++ 03 ซึ่งเป็นภาษาที่กำหนดไว้เมื่อ 15 ปีก่อน
Lightness Races ในวงโคจร


1

สมาชิกคลาสทั้งหมดเป็นแบบส่วนตัวโดยค่าเริ่มต้นและสมาชิกโครงสร้างทั้งหมดเป็นแบบสาธารณะโดยค่าเริ่มต้น ชั้นมีฐานส่วนตัวเริ่มต้นและโครงสร้างมีฐานสาธารณะเริ่มต้น โครงสร้างในกรณีของ C ไม่สามารถมีฟังก์ชั่นสมาชิกซึ่งในกรณีของ C ++ เราสามารถเพิ่มฟังก์ชันสมาชิกได้ในโครงสร้าง นอกเหนือจากความแตกต่างเหล่านี้ฉันไม่พบสิ่งที่น่าแปลกใจเกี่ยวกับพวกเขา


0

ฉันใช้ struct เฉพาะเมื่อฉันต้องการเก็บข้อมูลบางอย่างโดยไม่มีฟังก์ชั่นสมาชิกใด ๆ ที่เกี่ยวข้อง (เพื่อดำเนินการกับข้อมูลสมาชิก) และเข้าถึงตัวแปรข้อมูลโดยตรง

เช่นการอ่าน / เขียนข้อมูลจากไฟล์และสตรีมซ็อกเก็ตเป็นต้นการส่งผ่านอาร์กิวเมนต์ของฟังก์ชันในโครงสร้างที่อาร์กิวเมนต์ของฟังก์ชันมีมากเกินไปและไวยากรณ์ของฟังก์ชันดูยาวเกินไป

ในทางเทคนิคไม่มีความแตกต่างใหญ่ระหว่างคลาสและ struture ยกเว้นการเข้าถึงที่เป็นค่าเริ่มต้น มากกว่านั้นขึ้นอยู่กับสไตล์การเขียนโปรแกรมที่คุณใช้


-4

ฉันคิดว่า Structs มีจุดประสงค์เพื่อเป็นโครงสร้างข้อมูล (เช่นชุดข้อมูลหลายประเภท) และชั้นเรียนถูกใช้สำหรับการบรรจุรหัส (เช่นชุดของรูทีนย่อยและฟังก์ชั่น) ..

:(


-6

ฉันไม่เคยใช้ "struct" ใน C ++

ฉันไม่สามารถจินตนาการถึงสถานการณ์ที่คุณจะใช้โครงสร้างเมื่อคุณต้องการให้สมาชิกส่วนตัวเว้นแต่คุณจะพยายามทำให้สับสน

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

เช่น

class PublicInputData {
    //data members
 };

ตามที่ฉัน "บ่งชี้วากยสัมพันธ์ของวิธีการใช้ข้อมูล" เป็นเหตุผลที่ดีอย่างสมบูรณ์แบบที่จะใช้ struct โดยเฉพาะอย่างยิ่งถ้าทางเลือกคือการใช้ความคิดเห็นหรือชื่อในชื่อ classname
Viktor Sehr

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