ฉันพบว่าสหภาพ C ++ ค่อนข้างเจ๋ง ดูเหมือนว่าผู้คนมักจะนึกถึงกรณีการใช้งานที่ต้องการเปลี่ยนค่าของอินสแตนซ์แบบร่วม "ในสถานที่" เท่านั้น (ซึ่งดูเหมือนว่าจะทำหน้าที่เพียงบันทึกหน่วยความจำหรือทำการแปลงที่น่าสงสัยเท่านั้น)
ในความเป็นจริงสหภาพแรงงานสามารถของพลังอันยิ่งใหญ่เป็นเครื่องมือวิศวกรรมซอฟต์แวร์, แม้ในขณะที่คุณไม่เคยเปลี่ยนค่าของอินสแตนซ์ยูเนี่ยนใด ๆ
ใช้กรณีที่ 1: กิ้งก่า
ด้วยสหภาพแรงงานคุณสามารถจัดกลุ่มคลาสตามอำเภอใจจำนวนหนึ่งใหม่ภายใต้นิกายเดียวซึ่งไม่ได้ไม่มีความคล้ายคลึงกับกรณีของคลาสพื้นฐานและคลาสที่ได้รับ อย่างไรก็ตามสิ่งที่เปลี่ยนแปลงคือสิ่งที่คุณทำได้และไม่สามารถทำได้กับอินสแตนซ์สหภาพที่กำหนด:
struct Batman;
struct BaseballBat;
union Bat
{
Batman brucewayne;
BaseballBat club;
};
ReturnType1 f(void)
{
BaseballBat bb = {};
Bat b;
b.club = bb;
}
ReturnType2 g(Bat& b)
{
}
Bat returnsBat(void);
ReturnType3 h(void)
{
Bat b = returnsBat();
}
ดูเหมือนว่าโปรแกรมเมอร์จะต้องมั่นใจถึงประเภทของเนื้อหาของอินสแตนซ์สหภาพที่กำหนดเมื่อต้องการใช้ เป็นกรณีในฟังก์ชันf
ข้างต้น อย่างไรก็ตามหากฟังก์ชันได้รับอินสแตนซ์แบบร่วมเป็นอาร์กิวเมนต์ที่ผ่านแล้วเช่นเดียวกับกรณีg
ข้างต้นก็จะไม่รู้ว่าจะทำอย่างไรกับมัน เช่นเดียวกับฟังก์ชันที่ส่งคืนอินสแตนซ์แบบร่วมโปรดดูh
: ผู้โทรรู้ได้อย่างไรว่ามีอะไรอยู่ข้างใน?
หากอินสแตนซ์แบบสหภาพไม่เคยถูกส่งผ่านเป็นอาร์กิวเมนต์หรือเป็นค่าส่งคืนก็จะต้องมีชีวิตที่น่าเบื่อหน่ายมากพร้อมกับความตื่นเต้นที่เพิ่มขึ้นอย่างรวดเร็วเมื่อโปรแกรมเมอร์เลือกที่จะเปลี่ยนเนื้อหา:
Batman bm = {};
Baseball bb = {};
Bat b;
b.brucewayne = bm;
b.club = bb;
และนั่นคือกรณีการใช้งานที่เป็นที่นิยมมากที่สุด (un) ของสหภาพแรงงาน การใช้งานอีกกรณีหนึ่งคือเมื่ออินสแตนซ์แบบร่วมมาพร้อมกับสิ่งที่บอกประเภทของมัน
ใช้กรณีที่ 2: "ยินดีที่ได้รู้จักฉันobject
มาจากClass
"
สมมติว่าโปรแกรมเมอร์คนหนึ่งเลือกที่จะจับคู่อินสแตนซ์ยูเนี่ยนกับตัวบอกประเภทเสมอ (ฉันจะปล่อยให้เป็นดุลยพินิจของผู้อ่านในการจินตนาการถึงการนำไปใช้สำหรับวัตถุดังกล่าว) สิ่งนี้จะเอาชนะจุดประสงค์ของการรวมตัวเองหากสิ่งที่โปรแกรมเมอร์ต้องการคือการบันทึกหน่วยความจำและขนาดของตัวบอกประเภทนั้นไม่สำคัญกับสหภาพแรงงาน แต่สมมติว่ามันสำคัญมากที่อินสแตนซ์ของสหภาพสามารถส่งผ่านเป็นอาร์กิวเมนต์หรือเป็นค่าส่งคืนโดยที่ผู้เรียกหรือผู้โทรไม่รู้ว่ามีอะไรอยู่ข้างใน
จากนั้นโปรแกรมเมอร์จะต้องเขียนswitch
คำสั่งโฟลว์การควบคุมเพื่อบอกให้บรูซเวย์นแตกต่างจากแท่งไม้หรือสิ่งที่เทียบเท่า มันไม่ได้แย่เกินไปเมื่อมีเนื้อหาเพียงสองประเภทในสหภาพ แต่เห็นได้ชัดว่าสหภาพไม่ได้ขยายขนาดอีกต่อไป
ใช้กรณีที่ 3:
ในฐานะผู้เขียนข้อเสนอแนะสำหรับมาตรฐาน ISO C ++ได้กล่าวไว้ในปี 2008
โดเมนปัญหาที่สำคัญจำนวนมากต้องการวัตถุจำนวนมากหรือทรัพยากรหน่วยความจำที่ จำกัด ในสถานการณ์เหล่านี้การอนุรักษ์พื้นที่เป็นสิ่งสำคัญมากและการรวมกลุ่มกันมักจะเป็นวิธีที่สมบูรณ์แบบในการทำเช่นนั้น ในความเป็นจริงกรณีการใช้งานทั่วไปคือสถานการณ์ที่สหภาพแรงงานไม่เคยเปลี่ยนสมาชิกที่ใช้งานอยู่ตลอดอายุการใช้งาน สามารถสร้างคัดลอกและทำลายได้ราวกับว่าเป็นโครงสร้างที่มีสมาชิกเพียงคนเดียว การประยุกต์ใช้โดยทั่วไปของสิ่งนี้คือการสร้างคอลเลกชันที่แตกต่างกันของประเภทที่ไม่เกี่ยวข้องซึ่งไม่ได้รับการจัดสรรแบบไดนามิก (บางทีอาจถูกสร้างขึ้นในตำแหน่งในแผนที่หรือสมาชิกของอาร์เรย์)
และตอนนี้ตัวอย่างที่มีแผนภาพคลาส UML:
สถานการณ์ในภาษาอังกฤษธรรมดา: ออบเจ็กต์ของคลาส A สามารถมีอ็อบเจ็กต์ของคลาสใดก็ได้ในหมู่ B1, ... , Bn และอย่างน้อยหนึ่งประเภทในแต่ละประเภทโดยnเป็นจำนวนที่ค่อนข้างมากให้พูดอย่างน้อย 10
เราไม่ต้องการเพิ่มฟิลด์ (สมาชิกข้อมูล) ใน A เช่นนี้:
private:
B1 b1;
.
.
.
Bn bn;
เนื่องจากnอาจแตกต่างกันไป (เราอาจต้องการเพิ่มคลาส Bx ในการผสม) และเนื่องจากสิ่งนี้จะทำให้เกิดความยุ่งเหยิงกับตัวสร้างและเนื่องจากวัตถุ A จะใช้พื้นที่มาก
เราสามารถใช้คอนเทนเนอร์พvoid*
อยน์เตอร์ที่แปลกประหลาดไปยังBx
วัตถุที่มีการร่ายเพื่อดึงมา แต่มันก็น่ากลัวและเป็นแบบ C ... แต่ที่สำคัญกว่านั้นจะทำให้เรามีอายุขัยของวัตถุที่จัดสรรแบบไดนามิกจำนวนมากเพื่อจัดการ
สิ่งที่สามารถทำได้คือ:
union Bee
{
B1 b1;
.
.
.
Bn bn;
};
enum BeesTypes { TYPE_B1, ..., TYPE_BN };
class A
{
private:
std::unordered_map<int, Bee> data;
public:
Bee get(int);
};
จากนั้นในการรับเนื้อหาของอินสแตนซ์แบบร่วมจากdata
คุณใช้a.get(TYPE_B2).b2
และไลค์อินสแตนซ์a
คลาสA
อยู่ที่ไหน
ทั้งหมดนี้มีประสิทธิภาพมากขึ้นเนื่องจากสหภาพแรงงานไม่ถูก จำกัด ใน C ++ 11 ดูเอกสารที่ลิงก์ด้านบนหรือบทความนี้เพื่อดูรายละเอียด