ตัวทำลายเสมือนใน C ++

Taw Thalay Semuxn Ni C



C++ เป็นภาษาที่ใช้เป็นพื้นฐานในแนวคิดพื้นฐานของการเขียนโปรแกรม และทำให้ความคิดเชิงตรรกะของโปรแกรมเมอร์แข็งแกร่ง ใน C++ OOP มีบทบาทสำคัญเนื่องจาก OOP เป็นภาษาเชิงวัตถุที่สร้างวัตถุของคลาส ใน OOP เราศึกษาคลาสและอ็อบเจกต์ คลาสประกอบด้วยสมาชิกข้อมูลที่เป็นตัวแปรประเภทต่างๆ และฟังก์ชันของสมาชิกที่แตกต่างกัน ด้วยความช่วยเหลือของอินสแตนซ์ เราเข้าถึงข้อมูลของคลาสใดก็ได้ ทุกคลาสมีตัวสร้างและตัวทำลายเมื่อคุณสร้างคลาส ตัวสร้างจะถูกเรียกตัวเองเมื่อสร้างวัตถุของคลาสนั้น เรายังสามารถเริ่มต้นตัวแปรของคลาสภายในตัวสร้าง ตัวทำลายจะถูกสร้างขึ้นโดยอัตโนมัติด้วยตัวสร้าง แต่ตัวทำลายจะทำลายวัตถุและเป็นฟังก์ชันสุดท้ายที่ถูกเรียกก่อนที่จะทำลายวัตถุ ชื่อของคลาส เช่น คลาส 'Profession' จะถูกสร้างขึ้น ตัวสร้างของมันคือ Profession() และตัวทำลายคือ ~Profession () พวกเขาทั้งสามคนมีชื่อเหมือนกัน

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

เหตุใดเราจึงใช้ Virtual Destructor

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

ตัวอย่างพื้นฐาน C ++ ที่ไม่มี Virtual Destructor

มาดูกันว่าโปรแกรมทำงานอย่างไรโดยไม่มีตัวทำลายเสมือนด้วยโปรแกรมง่ายๆ ที่ลบพอยน์เตอร์

รหัส:

#รวมถึง

ใช้เนมสเปซมาตรฐาน ;
คลาส Parent_Class0
{
สาธารณะ :
Parent_Class0 ( )
{ ศาล << 'ตัวสร้างคลาสผู้ปกครอง' << จบ ; }
~Parent_Class0 ( )
{ ศาล << 'ตัวทำลายระดับผู้ปกครอง' << จบ ; }
} ;
ชั้น Child_1 : Parent_Class0 สาธารณะ
{
สาธารณะ :
ชายด์_1 ( )
{ ศาล << 'ตัวสร้างคลาสลูก' << จบ ; }
~เด็ก_1 ( )
{ ศาล << 'ตัวทำลายคลาสเด็ก' << จบ ; }
} ;
นานาชาติ หลัก ( )
{
Parent_Class0 * ตัวชี้ = ใหม่ Child_1 ( ) ;
ลบตัวชี้ ;
กลับ 0 ;
}

โค้ดนี้อธิบายถึงวิธีการรันโค้ดโดยไม่มีตัวทำลายเสมือน ก่อนอื่น สร้างคลาสชื่อ “Parent_Class0” ซึ่งจะเป็นคลาสพาเรนต์ ภายในคลาสนี้ ให้สร้างตัวสร้างและตัวทำลาย ดังที่เราทราบ ตัวสร้างและตัวทำลายมีชื่อเหมือนกับคลาส destructor แสดงคล้ายกับตัวสร้าง แต่มีสัญลักษณ์ (~) ที่แตกต่างจากตัวสร้าง ภายในตัวสร้างและตัวทำลาย ให้พิมพ์ข้อความโดยใช้ “cout<<” ตอนนี้ สร้างชั้นเรียนใหม่ซึ่งก็คือ “Child_1” คลาสนี้มาจากคลาสพาเรนต์ “Parent_Class0” คลาสที่ได้รับมีตัวสร้างและตัวทำลายที่มีข้อความที่จะพิมพ์บนหน้าจอเอาต์พุต

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

เอาท์พุต:

ตัวอย่าง C ++ พร้อม Virtual Destructor

เรามาพูดถึงตัวทำลายเสมือนด้วยรหัสง่ายๆ เพื่อแยกความแตกต่างว่ามันทำงานอย่างไรโดยมีและไม่มีตัวทำลายเสมือน

รหัส:

#รวมถึง

ใช้เนมสเปซมาตรฐาน ;
คลาส Parent_Class0
{
สาธารณะ :
Parent_Class0 ( )
{ ศาล << 'ตัวสร้างคลาสผู้ปกครอง' << จบ ; }
เสมือน ~ Parent_Class0 ( )
{ ศาล << 'ตัวทำลายระดับผู้ปกครอง' << จบ ; }
} ;
ชั้น Child_1 : Parent_Class0 สาธารณะ
{
สาธารณะ :
ชายด์_1 ( )
{ ศาล << 'ตัวสร้างคลาสลูก' << จบ ; }
เสมือน ~Child_1 ( )
{ ศาล << 'ตัวทำลายคลาสเด็ก' << จบ ; }
} ;
นานาชาติ หลัก ( )
{
Parent_Class0 * ตัวชี้ = ใหม่ Child_1 ( ) ;
ลบตัวชี้ ;
กลับ 0 ;
}

โปรแกรมแรกอธิบายปัญหาที่เรากำลังเผชิญอยู่โดยไม่มีตัวทำลายเสมือน ตอนนี้รหัสนี้จะแก้ปัญหานั้นโดยใช้ตัวทำลายเสมือน ขั้นแรก ให้คัดลอกรหัสแรกและเพิ่มคำสำคัญหนึ่งคำในสองที่ในโปรแกรมนี้ คำนั้นคือ 'เสมือน' แทรกคำนี้ด้วยตัวทำลายของคลาสพาเรนต์ “Parent_Class0” ในทำนองเดียวกัน ให้พูดถึงสิ่งนี้กับตัวทำลายของคลาสลูกซึ่งก็คือ “Child_1” ที่ได้มาจากคลาสพาเรนต์ คำหลัก 'เสมือน' นี้ทำการเปลี่ยนแปลงเล็กน้อยและเรียกใช้ตัวทำลายของคลาสย่อย 'Child_1' ก่อน จากนั้นรันตัวทำลายของคลาสพาเรนต์ “Parent_Class0” โปรแกรมที่เหลือทำงานแบบเดียวกับที่ทำงานโดยไม่มีตัวทำลายเสมือน ด้วยการเพิ่มโค้ดส่วนเล็กๆ นี้ เราสามารถรักษาหน่วยความจำของเราไม่ให้รั่วไหลได้ ตอนนี้จะแสดงสี่ข้อความบนคอนโซล ขั้นแรก คอนสตรัคเตอร์ของคลาสพาเรนต์ จากนั้นคอนสตรัคเตอร์ของคลาสย่อย ตัวทำลายของคลาสย่อย และตัวทำลายของคลาสพาเรนต์ ในตอนท้าย เราลบตัวชี้ภายในเมธอด main()

เอาท์พุต:

ตัวอย่าง C ++ ของ Pure Virtual Destructor

ในโค้ดนี้ เราจะพูดถึงตัวทำลายเสมือนล้วน วิธีการทำงาน และความแตกต่างจากตัวทำลายเสมือน

รหัส:

#รวมถึง

คลาส Parent_0 {
สาธารณะ :
เสมือน ~Parent_0 ( ) = 0 ;
} ;
Parent_0 :: ~ผู้ปกครอง_0 ( )
{
มาตรฐาน :: ศาล << 'สวัสดี ฉันคือ Pure Destructor คุณเรียกฉันว่า!' ;
}
คลาส Child_0 : สาธารณะ Parent_0 {
สาธารณะ :
~เด็ก_0 ( ) { มาตรฐาน :: ศาล << 'ตัวทำลายที่ได้มาอยู่ที่นี่ \n ' ; }
} ;

นานาชาติ หลัก ( )
{
Parent_0 * ptr_0 = ใหม่ Child_0 ( ) ;
ลบ ptr_0 ;
กลับ 0 ;
}

คลาสพาเรนต์ “Parent_0” ถูกสร้างขึ้นในขั้นตอนแรกของโค้ด ภายในนั้น ให้สร้าง virtual parent destructor และกำหนดด้วย 0 ซึ่งกำหนดให้ virtual destructor เป็น virtual destructor อย่างแท้จริง ซึ่งหมายความว่าตอนนี้คลาส parent เป็นนามธรรมแล้ว และเราไม่สามารถสร้างอินสแตนซ์ของคลาสนี้ได้ นอกคลาสพาเรนต์ “Parent_0” ให้กำหนด destructors และ std::cout ข้อความที่ต้องการแสดงโดยใช้ std::cout จากนั้น รับคลาส “Child_0” จากคลาสพาเรนต์และกำหนดตัวทำลาย ภายใน destructor ให้พิมพ์ข้อความ ในฟังก์ชัน main() ให้สร้างตัวชี้ของคลาสพาเรนต์และกำหนดคลาสย่อยให้

คอมไพเลอร์ไปที่คลาสพาเรนต์ “Parent_0” เมื่อตัวชี้ถูกสร้างขึ้น ตัวสร้างจะถูกเรียกใช้โดยอัตโนมัติ จากนั้น คอมไพเลอร์จะเข้าสู่คลาสลูกเพื่อเรียกใช้คอนสตรัคเตอร์ หลังจากดำเนินการคอนสตรัคเตอร์สำเร็จแล้ว รันตัวทำลายของคลาสย่อย “Child_0” จากนั้นจะดำเนินการตัวทำลายของคลาสพาเรนต์ ด้วยวิธีนี้ เราสามารถสร้างตัวทำลายเสมือนจริงอย่างแท้จริง ไม่สนับสนุนให้ใช้เพราะใช้วิธีนี้ คลาสพาเรนต์จะกลายเป็นนามธรรมซึ่งทำให้ไร้ประโยชน์ วิธีการที่ใช้ส่วนใหญ่เป็นตัวทำลายเสมือนและเป็นแนวปฏิบัติที่ดี

เอาท์พุต:

บทสรุป

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