ในC ++มีความแตกต่างระหว่าง:
struct Foo { ... };
และ:
typedef struct { ... } Foo;
ในC ++มีความแตกต่างระหว่าง:
struct Foo { ... };
และ:
typedef struct { ... } Foo;
คำตอบ:
ใน C ++ มีความแตกต่างเพียงเล็กน้อยเท่านั้น มันเป็นสิ่งที่หลงเหลือจาก C ซึ่งมันสร้างความแตกต่าง
มาตรฐานภาษา C ( C89 .13.1.2.3 , C99 §6.2.3และC11 §6.2.3 ) กำหนดหน้าที่แยกชื่อสำหรับประเภทตัวระบุต่าง ๆ รวมถึงตัวระบุแท็ก (สำหรับstruct
/ union
/ enum
) และตัวระบุสามัญ (สำหรับtypedef
และตัวระบุอื่น ๆ ) .
หากคุณเพิ่งพูดว่า:
struct Foo { ... };
Foo x;
คุณจะได้รับข้อผิดพลาดของคอมไพเลอร์เนื่องจากFoo
กำหนดไว้ในแท็กเนมสเปซเท่านั้น
คุณต้องประกาศว่า:
struct Foo x;
เมื่อใดก็ตามที่คุณต้องการที่จะหมายถึงคุณจะต้องเรียกมันว่าFoo
struct Foo
สิ่งนี้จะน่ารำคาญอย่างรวดเร็วดังนั้นคุณสามารถเพิ่มtypedef
:
struct Foo { ... };
typedef struct Foo Foo;
ตอนนี้struct Foo
(ในแท็กเนมสเปซ) และเพียงธรรมดาFoo
(ในเนมสเปซตัวระบุธรรมดา) ทั้งคู่อ้างถึงสิ่งเดียวกันและคุณสามารถประกาศออบเจ็กต์ประเภทที่Foo
ไม่มีstruct
คำหลักได้อย่างอิสระ
โครงสร้าง:
typedef struct Foo { ... } Foo;
typedef
เป็นเพียงย่อสำหรับการประกาศและ
สุดท้าย
typedef struct { ... } Foo;
ประกาศโครงสร้างที่ไม่ระบุชื่อและสร้างtypedef
มันขึ้นมา ดังนั้นด้วยโครงสร้างนี้จึงไม่มีชื่อในแท็กเนมสเปซเฉพาะชื่อในเนมสเปซ typedef นี่หมายความว่าไม่สามารถประกาศล่วงหน้าได้ หากคุณต้องการที่จะทำให้การประกาศไปข้างหน้าคุณต้องให้มันชื่อใน namespace
ใน C ++ การประกาศทั้งหมดstruct
/ union
/ enum
/ class
ทำหน้าที่เหมือนเป็นการบอกนัยโดยปริยายtypedef
ตราบใดที่ชื่อไม่ถูกซ่อนโดยการประกาศอื่นที่มีชื่อเหมือนกัน ดูคำตอบของ Michael Burrสำหรับรายละเอียดทั้งหมด
ในบทความ DDJ นี้ Dan Saks อธิบายพื้นที่เล็ก ๆ แห่งหนึ่งที่ซึ่งแมลงสามารถคืบคลานผ่านไปได้หากคุณไม่พิมพ์ structs ของคุณ (และคลาส!):
หากคุณต้องการคุณสามารถจินตนาการได้ว่า C ++ สร้าง typedef สำหรับทุกชื่อแท็กเช่น
typedef class string string;
น่าเสียดายที่นี่ไม่ถูกต้องทั้งหมด ฉันหวังว่ามันจะง่าย แต่ก็ไม่ใช่ C ++ ไม่สามารถสร้าง typedefs ดังกล่าวสำหรับ struct, unions หรือ enums โดยไม่ต้องแนะนำความไม่ลงรอยกันกับ C
ตัวอย่างเช่นสมมติว่าโปรแกรม C ประกาศทั้งฟังก์ชั่นและโครงสร้างชื่อสถานะ:
int status(); struct status;
อีกครั้งนี่อาจเป็นการฝึกฝนที่ไม่ดี แต่มันคือ C ในโปรแกรมนี้สถานะ (โดยตัวมันเอง) หมายถึงฟังก์ชัน สถานะ struct หมายถึงประเภท
หาก C ++ สร้าง typedefs โดยอัตโนมัติสำหรับแท็กดังนั้นเมื่อคุณคอมไพล์โปรแกรมนี้เป็น C ++ คอมไพเลอร์จะสร้าง:
typedef struct status status;
น่าเสียดายที่ชื่อประเภทนี้ขัดแย้งกับชื่อฟังก์ชันและโปรแกรมจะไม่คอมไพล์ นั่นเป็นเหตุผลที่ C ++ ไม่สามารถสร้าง typedef สำหรับแต่ละแท็กได้
ใน C ++ แท็กทำหน้าที่เหมือนกับชื่อ typedef ยกเว้นว่าโปรแกรมสามารถประกาศวัตถุฟังก์ชันหรือตัวแจงนับที่มีชื่อเดียวกันและขอบเขตเดียวกับแท็ก ในกรณีนั้นวัตถุฟังก์ชันหรือชื่อตัวระบุจะซ่อนชื่อแท็ก โปรแกรมสามารถอ้างถึงชื่อแท็กโดยใช้คลาสคีย์เวิร์ด, struct, union หรือ enum (ตามความเหมาะสม) หน้าชื่อแท็ก ชื่อประเภทประกอบด้วยหนึ่งในคำหลักเหล่านี้ตามด้วยแท็กเป็นตัวระบุชนิดที่ซับซ้อน ตัวอย่างเช่นสถานะโครงสร้างและเดือน enum เป็นตัวระบุชนิดที่ซับซ้อน
ดังนั้นโปรแกรม C ที่มีทั้ง:
int status(); struct status;
ทำงานเหมือนกันเมื่อคอมไพล์เป็น C ++ สถานะชื่อคนเดียวหมายถึงฟังก์ชั่น โปรแกรมสามารถอ้างถึงชนิดเท่านั้นโดยใช้สถานะโครงสร้าง elaborated-type-specifier
ดังนั้นวิธีนี้จะช่วยให้ข้อบกพร่องเพื่อคืบเข้าไปในโปรแกรม? พิจารณาโปรแกรมใน รายชื่อ 1 โปรแกรมนี้กำหนด class foo ด้วยตัวสร้างค่าเริ่มต้นและตัวดำเนินการแปลงที่แปลงวัตถุ foo เป็น char const * การแสดงออก
p = foo();
ในหลักควรสร้างวัตถุ foo และใช้ตัวดำเนินการแปลง คำสั่งเอาต์พุตที่ตามมา
cout << p << '\n';
ควรแสดงคลาส foo แต่ไม่แสดง มันแสดงฟังก์ชั่น foo
นี้ผลที่น่าแปลกใจเกิดขึ้นเนื่องจากโปรแกรมรวมถึงส่วนหัว lib.h แสดงในรายชื่อ 2 ส่วนหัวนี้กำหนดฟังก์ชั่นชื่อฟู ชื่อฟังก์ชัน foo ซ่อนชื่อคลาส foo ดังนั้นการอ้างอิงถึง foo ใน main หมายถึงฟังก์ชันไม่ใช่คลาส main สามารถอ้างถึงคลาสเท่านั้นโดยใช้ตัวระบุชนิดที่ซับซ้อนเช่นเดียวกับใน
p = class foo();
วิธีที่จะหลีกเลี่ยงความสับสนดังกล่าวตลอดทั้งโปรแกรมคือการเพิ่ม typedef ต่อไปนี้สำหรับชื่อคลาส foo:
typedef class foo foo;
ทันทีก่อนหรือหลังคำจำกัดความของคลาส typedef นี้ทำให้เกิดข้อขัดแย้งระหว่างชื่อประเภท foo และชื่อฟังก์ชัน foo (จากไลบรารี) ที่จะทริกเกอร์ข้อผิดพลาดในการคอมไพล์เวลา
ฉันรู้ว่าไม่มีใครที่จริง ๆ แล้วพิมพ์ typedefs แน่นอน มันต้องมีวินัยมาก เนื่องจากอุบัติการณ์ของข้อผิดพลาดเช่นรายการ 1อาจมีขนาดค่อนข้างเล็กคุณหลายคนไม่เคยประสบปัญหานี้ แต่หากมีข้อผิดพลาดในซอฟต์แวร์ของคุณอาจทำให้เกิดการบาดเจ็บทางร่างกายคุณควรเขียน typedefs ไม่ว่าข้อผิดพลาดจะเกิดขึ้นได้อย่างไร
ฉันไม่สามารถจินตนาการได้ว่าทำไมทุกคนต้องการซ่อนชื่อคลาสด้วยฟังก์ชันหรือชื่อวัตถุในขอบเขตเดียวกับคลาส กฎการซ่อนใน C เป็นข้อผิดพลาดและไม่ควรขยายไปยังคลาสใน C ++ แน่นอนคุณสามารถแก้ไขข้อผิดพลาดได้ แต่ต้องมีวินัยในการเขียนโปรแกรมเพิ่มเติมและความพยายามที่ไม่จำเป็น
Listing 1
และListing 2
ลิงก์ต่าง ๆ ก็พัง ได้ดู
ความแตกต่างที่สำคัญอีกประการหนึ่ง: typedef
ไม่สามารถประกาศล่วงหน้าได้ ดังนั้นสำหรับtypedef
ตัวเลือกที่คุณต้อง#include
มีไฟล์ซึ่งtypedef
หมายถึงทุกอย่างที่#include
คุณ.h
มีรวมถึงไฟล์นั้นไม่ว่ามันจะต้องการโดยตรงหรือไม่และอื่น ๆ มันสามารถส่งผลกระทบต่อเวลาสร้างของคุณในโครงการขนาดใหญ่ได้อย่างแน่นอน
หากไม่มีtypedef
ในบางกรณีคุณสามารถเพิ่มการประกาศไปข้างหน้าของstruct Foo;
ที่ด้านบนของ.h
ไฟล์ของคุณและเพียง#include
นิยาม struct ใน.cpp
ไฟล์ของคุณ
มีคือความแตกต่าง แต่ลึกซึ้ง ดูด้วยวิธีนี้: struct Foo
แนะนำประเภทใหม่ อันที่สองสร้างนามแฝงที่เรียกว่า Foo (ไม่ใช่ประเภทใหม่) สำหรับstruct
ประเภทที่ไม่มีชื่อ
7.1.3 ตัวระบุ typedef
1 [... ]
ชื่อที่ประกาศพร้อมตัวระบุ typedef จะกลายเป็นชื่อ typedef ภายในขอบเขตของการประกาศ typedef-name จะเทียบเท่ากับคำหลักและชื่อประเภทที่เกี่ยวข้องกับตัวระบุในวิธีที่อธิบายไว้ในข้อ 8 typedef ชื่อจึงเป็นคำพ้องสำหรับประเภทอื่น ชื่อ typedef ไม่แนะนำชนิดใหม่ในลักษณะที่การประกาศคลาส (9.1) หรือการประกาศ enum
8 หากการประกาศ typedef กำหนดคลาสที่ไม่มีชื่อ (หรือ enum) ชื่อ typedef- แรกที่ประกาศโดยการประกาศว่าเป็นประเภทคลาส (หรือประเภท enum) จะใช้เพื่อแสดงประเภทคลาส (หรือประเภท enum) เพื่อจุดประสงค์ในการเชื่อมโยงเท่านั้น ( 3.5) [ตัวอย่าง:
typedef struct { } *ps, S; // S is the class name for linkage purposes
ดังนั้น typedef จะถูกใช้เป็นตัวยึด / คำพ้องสำหรับประเภทอื่นเสมอ
คุณไม่สามารถใช้การประกาศไปข้างหน้ากับโครงสร้าง typedef
struct เองเป็นชนิดที่ไม่ระบุชื่อดังนั้นคุณไม่มีชื่อจริงที่จะส่งต่อประกาศ
typedef struct{
int one;
int two;
}myStruct;
ประกาศไปข้างหน้าเช่นนี้จะไม่ทำงาน:
struct myStruct; //forward declaration fails
void blah(myStruct* pStruct);
//error C2371: 'myStruct' : redefinition; different basic types
myStruct
อาศัยอยู่ในแท็กเนมสเปซและ typedef_ed myStruct
อาศัยอยู่ในเนมสเปซปกติที่ตัวระบุอื่น ๆ เช่นชื่อฟังก์ชั่นชื่อตัวแปรท้องถิ่นอาศัยอยู่ดังนั้นจึงไม่ควรมีข้อขัดแย้งใด ๆ .. ฉันสามารถแสดงรหัสของฉันถ้าคุณสงสัยว่ามีข้อผิดพลาด
typedef
ประกาศไปข้างหน้าด้วยtypedef
ชื่อ ed ไม่ได้อ้างถึงโครงสร้างที่ไม่มีชื่อ myStruct
แทนการประกาศไปข้างหน้าประกาศโครงสร้างที่ไม่สมบูรณ์ที่มีแท็ก นอกจากนี้หากไม่เห็นคำจำกัดความของtypedef
ต้นแบบฟังก์ชั่นที่ใช้typedef
ชื่อ ed ไม่ถูกกฎหมาย ดังนั้นเราต้องรวม typedef ทั้งหมดเมื่อใดก็ตามที่เราจำเป็นต้องใช้myStruct
เพื่อแสดงประเภท ถูกต้องฉันถ้าฉันเข้าใจผิดคุณ ขอบคุณ
ความแตกต่างที่สำคัญระหว่าง 'typedef struct' และ 'struct' ใน C ++ คือการเริ่มต้นสมาชิกแบบอินไลน์ใน 'typedef structs' จะไม่ทำงาน
// the 'x' in this struct will NOT be initialised to zero
typedef struct { int x = 0; } Foo;
// the 'x' in this struct WILL be initialised to zero
struct Foo { int x = 0; };
x
มีการเริ่มต้น ดูการทดสอบใน Coliru ออนไลน์ IDE (ฉันเริ่มต้นได้ที่ 42 ดังนั้นจึงเห็นได้ชัดกว่าศูนย์ที่มีการมอบหมายจริง ๆ )
ไม่มีความแตกต่างใน C ++ แต่ฉันเชื่อใน C มันจะช่วยให้คุณสามารถประกาศอินสแตนซ์ของ struct Foo โดยไม่ต้องทำอย่างชัดเจน:
struct Foo bar;
โครงสร้างคือการสร้างชนิดข้อมูล typedef คือการตั้งชื่อเล่นสำหรับประเภทข้อมูล