c casts สไตล์หรือ c ++ style casts


21

ดังนั้นคุณใช้อะไร

int anInt = (int)aFloat;

หรือ

int anInt = static_cast<int>(aFloat);
// and its brethren

และที่สำคัญทำไม?

คำตอบ:


45

ก่อนอื่นให้ทำความเข้าใจว่าเส้นเหล่านั้นไม่เท่ากัน

int* anInt = (int*)aFloat; // is equivalent to

int* anInt = reinterpret_cast<int*>(aFloat); 

สิ่งที่เกิดขึ้นที่นี่คือโปรแกรมเมอร์กำลังขอให้คอมไพเลอร์ทำทุกอย่างเท่าที่ทำได้เพื่อสร้างนักแสดง

ข้อแตกต่างมีความสำคัญเนื่องจากการใช้ static_cast จะขอเฉพาะชนิดฐานที่ "ปลอดภัย" เพื่อทำการแปลงโดยที่ reinterpret_cast จะแปลงเป็นอะไรก็ได้โดยเพียงแค่จับคู่เค้าโครงหน่วยความจำที่ต้องการบนหน่วยความจำของวัตถุที่กำหนด

ดังนั้นในขณะที่ "ตัวกรอง" ไม่เหมือนกันการใช้การส่งแบบเจาะจงมีความชัดเจนและปลอดภัยกว่าการใช้การส่งแบบ C หากคุณต้องใช้คอมไพเลอร์ (หรือการใช้งานแบบรันไทม์หากคุณใช้ dynamic_cast) เพื่อบอกตำแหน่ง โดยหลีกเลี่ยง C cast และ reinterepret_cast

ตอนนี้ที่ว่านี้มีความชัดเจนมากขึ้นมีสิ่งอื่น: static_cast, reinterpret_cast, const_cast และ dynamic_cast จะง่ายต่อการค้นหา

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

นั่นคือ "โดยการออกแบบ" และนั่นทำให้นักพัฒนาซอฟต์แวร์ทราบว่าเขาสามารถทำสิ่งต่าง ๆ ได้ดีขึ้นอย่างไร (โดยการหลีกเลี่ยงการปลดเปลื้องหากไม่จำเป็นจริงๆ) และสถานที่ที่ดี แต่มันเป็น "เอกสาร" ในรหัสโดย "ทำเครื่องหมาย" มันน่าเกลียด

เหตุผลที่สองสำหรับการแนะนำนักแสดงสไตล์ใหม่คือการที่นักแสดงสไตล์ C นั้นยากที่จะมองเห็นในรายการ ตัวอย่างเช่นคุณไม่สามารถค้นหา cast ได้อย่างสะดวกโดยใช้โปรแกรมแก้ไขธรรมดาหรือโปรแกรมประมวลผลคำ สิ่งที่มองไม่เห็นอย่างใกล้ชิดของ C-style casts นี้เป็นเรื่องที่น่าเสียดายเป็นพิเศษเพราะมันอาจจะสร้างความเสียหายได้ การดำเนินการที่น่าเกลียดควรมีรูปแบบประโยคที่น่าเกลียด การสังเกตนั้นเป็นส่วนหนึ่งของเหตุผลในการเลือกไวยากรณ์สำหรับการปลดเปลื้องรูปแบบใหม่ เหตุผลเพิ่มเติมคือเพื่อให้ casts สไตล์ใหม่ตรงกับสัญลักษณ์ของเทมเพลตเพื่อให้โปรแกรมเมอร์สามารถเขียน casts ของตัวเองโดยเฉพาะ casts ที่ตรวจสอบรันไทม์

อาจเป็นเพราะ static_cast น่าเกลียดและค่อนข้างยากที่จะพิมพ์คุณมีแนวโน้มที่จะคิดสองครั้งก่อนใช้ใช่ไหม นั่นน่าจะดีเพราะนักแสดงส่วนใหญ่จะหลีกเลี่ยงใน C ++ ที่ทันสมัย

ที่มา: Bjarne Stroustrup (ผู้สร้าง C ++)


2
ฉันจะลงคะแนนถ้าฉันมีคะแนนอีกไม่กี่ แต่น่าเสียดายที่ฉันไม่สามารถ การปลดเปลื้องแบบ c จะไม่เทียบเท่า reinterpret_cast reinterpret_cast<int>(double);พิจารณา มีความเป็นไปได้อย่างมากที่จะส่งออกเป็นสองเท่าไปยัง int ด้วยการส่งแบบ c-style แต่ไม่สามารถทำได้ด้วย reinterpret_cast ฉันเห็น Timbo ชี้ไปที่คุณแล้วและคุณบอกว่าคุณจะแก้ไขได้ แต่สี่ปีต่อมาก็ยังคงไม่ถูกต้อง ฉันจะยังคงลงคะแนนให้คุณถ้ามันได้รับการแก้ไขเนื่องจากมีเหตุผลที่สมบูรณ์แบบที่จำเป็นต้องใช้นักแสดง ต่อไปนี้เป็นคำตอบที่ดีกว่า: stackoverflow.com/a/332086/3878168
Yay295

36

การปลดเปลื้อง C ++ นั้นมีข้อ จำกัด มากขึ้น (ดังนั้นจงแสดงเจตนาของคุณให้ดีขึ้นและทำให้การตรวจสอบโค้ดง่ายขึ้น ฯลฯ ) นอกจากนี้ยังง่ายต่อการค้นหาหากคุณต้องการ


10
... และพวกเขามีแนวโน้มที่จะทำสิ่งที่คุณตั้งใจ ;-)
Macke

7
และพวกเขาก็มีอะไรให้พิมพ์อีกมากมายให้คุณอีกเหตุผลหนึ่งที่ทำให้ประเภทของคุณถูกต้องโดยไม่จำเป็นต้องปลดเปลื้อง
Michael Kohne

7
และพวกมันน่าเกลียดเป็นฟีเจอร์ทำให้เห็นได้ชัดเจนว่าในรหัสอาจมีจุดของการปรับปรุงหรือกรณีพิเศษที่อาจต้องใช้เอกสารประกอบ - แก้ไข: ว้าวฉันเพิ่งค้นพบว่าฉันตอบคำถามนี้ด้วย! XD
อ้างสิทธิ์

ตอนนี้ทำไมฉันต้องการค้นหาพวกเขา?
Deduplicator

@Dupuplicator มีสาเหตุหลายประการที่คุณอาจต้องการทราบว่ามีคาสต์เกิดอะไรขึ้นในรหัสฐาน ตัวอย่างเช่นเมื่อค้นหาข้อบกพร่องที่อาจเกี่ยวข้องกับการคัดเลือกนักแสดง (โดยเฉพาะเมื่อทำการพัฒนาข้ามแพลตฟอร์ม)
Klaim

13

ตัวเลือก C: การโยน "C ++ - สไตล์" เนื่องจากไม่สามารถแยกแยะได้จากสิ่งก่อสร้าง:

int anInt = int(aFloat);

หรือแม้กระทั่ง:

int anInt(aFloat);

นอกเหนือจากกรณีเล็ก ๆ น้อย ๆ เหล่านี้ที่มีพื้นฐานซึ่งเป็นที่เข้าใจกันแล้วฉันชอบที่จะใช้ x_cast <> s มากกว่าการฉายในสไตล์ C มีเหตุผลสามประการ:

  • พวกเขากำหนดการปฏิบัติการที่โปรแกรมเมอร์พยายามทำ

  • พวกเขาสามารถดำเนินการที่ C-style casts ไม่สามารถทำได้ (โดยเฉพาะอย่างยิ่งในกรณีของ dynamic_cast <> ซึ่งสามารถ cross-cast ข้ามสาขาของสายโซ่การสืบทอดหลายแบบ)

  • พวกเขาจะน่าเกลียด พวกเขาดังประกาศว่าโปรแกรมเมอร์กำลังทำงานกับระบบประเภท ในกรณีนี้มันเป็นสิ่งที่ดี


7

หากการเขียนโค้ดใน C ใช้ตัวเลือก C หากการเขียนใน C ++ ให้ใช้การร่าย C ++

ในขณะที่การคัดเลือกนักแสดงส่วนใหญ่แบ่งประเภทความปลอดภัยที่เหมาะสม แต่ตัว C ++ นั้นมีข้อ จำกัด มากกว่าดังนั้นคุณจึงไม่ปลอดภัยน้อยกว่าประเภทนักแสดง C

ฉันสามารถทนใครบางคนที่ใช้ (T *) NULL แม้ว่าจะบังคับให้เกินพิกัด ...


7

ฉันมีกฎบางอย่างเกี่ยวกับ C / C ++ - สไตล์การปลดเปลื้อง:

  1. Dis-ใช้ const ต้องเสมอconst_castใช้ ด้วยเหตุผลที่ชัดเจน น่าเศร้าที่กฎของฉันเกี่ยวกับการไม่ใช้ const ทำให้แป้นพิมพ์เอื้อมมือและทำลายนิ้วของโปรแกรมเมอร์ไม่ได้รับการอนุมัติ
  2. ใด ๆ reinterpret_castของแง่บิตจัดการสไตล์ที่โปรแกรมเมอร์รับได้ถึงเมื่อได้รับลงไปที่โลหะควรใช้ จริงๆแล้วมันเป็นนักแสดงประเภทที่ C ไม่มี: แกล้งบิตของจำนวนเต็มนี้จริง ๆ แล้วเป็นบิตของโฟลต (int)(*(int*)(&floatVar))หลีกเลี่ยงความไม่ราบรื่นเช่นนี้
  3. ถ้าคุณพิมพ์คำว่า " dynamic_cast" ให้หยุดและประเมินลำดับชั้นและการออกแบบคลาส polymorphic ของคุณใหม่ ประเมินการออกแบบลำดับชั้นของคลาสของคุณต่อไปจนกว่าคุณจะสามารถลบคำเหล่านั้นได้
  4. static_castไม่รำคาญกับ

เหตุผลที่อยู่เบื้องหลัง # 4 คือเพียงว่ามันไม่สำคัญ สถานการณ์ที่ไม่สอดคล้องกับกฎอื่น ๆ นั้นชัดเจนหรือต่ำจริงๆ การแปลงอย่างง่ายของชนิดง่าย ๆ เช่น int-to-float ไม่จำเป็นต้องใช้ไวยากรณ์พิเศษ และถ้าคุณลงไปในความลึกของสิ่งที่น่าเกลียดคุณก็ลงไปในความลึกของสิ่งที่น่าเกลียด ไม่จำเป็นต้องดึงความสนใจไปที่ความจริงที่ว่า "ที่นี่มีมังกร" ตั้งแต่ฟันกรงเล็บและไฟค่อนข้างทำให้มันหมดไปแล้ว


1
dynamic_castเป็นเครื่องมือที่ใช้ได้อย่างสมบูรณ์แบบ มีประโยชน์น้อยมากที่ฉันจะยอมรับ แต่มันอยู่ไกลจากซาตานในสิ่งต่าง ๆ เช่นตัวแปรทั่วโลก อย่างไรก็ตามในขั้นต้นฉันลงคะแนนให้คุณเพราะคุณไม่ได้ตอบคำถามซึ่งเกี่ยวกับการใช้งานหรือไม่ในการใช้งาน C-style
DeadMG

2
@DeadMG: ฉันพูดเกี่ยวกับ C-style casts ย่อหน้าสุดท้ายทั้งหมดแสดงให้เห็นว่า C-style casts สนับสนุน static_cast
Nicol Bolas

"น่าเศร้าที่กฎของฉันเกี่ยวกับการใช้ const ทำให้แป้นพิมพ์เอื้อมมือและทำลายนิ้วของโปรแกรมเมอร์ไม่ได้รับการอนุมัติ" ในทางเทคนิคแล้วการทำคอมไพเลอร์นั้นถูกต้องตามกฎหมาย การที่คอมไพเลอร์ทำให้ปีศาจบินออกจากจมูกของคุณอย่างถูกกฎหมาย
Pharap

4

เนื่องจากโพสต์ด้านบนให้สังเกตว่าการใช้งาน C ++ (คงที่) นั้นค่อนข้างปลอดภัยกว่าในทางปฏิบัติ

อาจเป็นเรื่องที่ฉลาดที่จะค้นหาข้อมูลเพิ่มเติมเกี่ยวกับการคัดเลือกนักแสดงประเภทต่าง ๆ รวมถึงข้อดีและข้อเสีย

เพียงแค่มีพื้นหลังเพิ่มเติมเกี่ยวกับสาเหตุ .

http://en.wikipedia.org/wiki/Static_cast

http://en.wikipedia.org/wiki/Dynamic_cast

http://en.wikipedia.org/wiki/Reinterpret_cast


3

มันขึ้นอยู่กับภาษาที่ฉันใช้ด้วยเพราะคุณรู้ว่าพวกเขาพูดอะไร: ในโรมพูดภาษาโรมัน ดังนั้นถ้าฉันเขียนโปรแกรมใน C ฉันพยายามใช้คุณสมบัติ C กับ max แต่ถ้าฉันเขียนโปรแกรมที่ C ++ ฉันไปข้างหน้าและใช้คุณสมบัติ C ++ กับ max แม้ว่าบางคนไม่ชอบวิธีการนี้เพราะ พวกเขาบอกว่ามันทำให้โค้ด "พกพาน้อยลง" ฉันบอกว่าฉันไม่สนใจฉันอยู่ใน C ++ และการเขียนโปรแกรมใน C ++ และฉันต้องการคอมไพเลอร์ที่เข้ากันได้อย่างเต็มที่ C ++ เพื่อคอมไพล์โค้ดมิฉะนั้นฉันจะทำงานร่วมกับ ในที่แรก.


มันใช้งานไม่ได้กับการลองใช้ C ++ - สไตล์การใช้งานใน C ;-)
Steve314

3

static_cast ฯลฯ ถูกคิดค้นเนื่องจากปัญหากับ cast สไตล์ C เมื่อใช้ในแม่แบบ หากคุณกำลังเขียนเทมเพลตหรือหากโค้ดของคุณอาจถูกแปลงเป็นเทมเพลตในภายหลังก็เป็นความคิดที่ดีที่จะใช้สไตล์ C ++ เหตุผลก็เพราะสไตล์ C ++ ปลดเปลื้องเจตนาที่ดีกว่าดังนั้นพวกเขาจะให้ผลลัพธ์ที่คาดหวังในกรณีที่สไตล์ C- สไตล์จะทำสิ่งผิด (ให้ประเภทเฉพาะเป็นพารามิเตอร์เทมเพลต)

นอกจากนั้นฉันบอกว่าใช้สไตล์ C ++ ถ้ามีปัญหาเฉพาะที่ต้องการพวกเขา - dynamic_cast เป็นเรื่องที่พบได้บ่อยที่สุด แต่ถึงแม้มันอาจไม่ใช่ทุกวันก็ตาม

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

หมายเหตุสุดท้าย - หากคุณต้องการปลดเปลื้องจำนวนมากว่านี่เป็นเรื่องใหญ่คุณอาจทำผิดอย่างอื่น มีข้อยกเว้นในบางกรณี แต่รหัสระดับสูงส่วนใหญ่ไม่ควรมีการปลดเปลื้องจำนวนมาก (ถ้ามี)

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