มรดก
จุดรวมของการสืบทอดคือการใช้อินเทอร์เฟซทั่วไปและโปรโตคอลร่วมกันระหว่างการนำไปใช้งานที่แตกต่างกันหลายอย่างเช่นอินสแตนซ์ของคลาสที่ได้รับสามารถรักษาเหมือนกันกับอินสแตนซ์อื่นจากประเภทอื่น ๆ
ในการสืบทอด C ++ ยังนำมาซึ่งรายละเอียดการใช้งานการทำเครื่องหมาย (หรือไม่ทำเครื่องหมาย) ตัวทำลายที่เสมือนเป็นหนึ่งในรายละเอียดการใช้งานดังกล่าว
ฟังก์ชั่นเข้าเล่ม
ตอนนี้เมื่อฟังก์ชั่นหรือกรณีพิเศษใด ๆ เช่นคอนสตรัคเตอร์หรือ destructor เรียกว่าคอมไพเลอร์จะต้องเลือกการใช้งานฟังก์ชั่นที่มีความหมาย จากนั้นจะต้องสร้างรหัสเครื่องที่ตามความตั้งใจนี้
วิธีที่ง่ายที่สุดในการทำงานคือเลือกฟังก์ชั่น ณ เวลาที่คอมไพล์แล้วปล่อยรหัสเครื่องให้เพียงพอโดยไม่คำนึงถึงค่าใด ๆ เมื่อประมวลผลโค้ดนั้นมันจะรันโค้ดสำหรับฟังก์ชั่นเสมอ มันใช้งานได้ดีมากยกเว้นการสืบทอด
ถ้าเรามีคลาสพื้นฐานที่มีฟังก์ชั่น (อาจเป็นฟังก์ชั่นใด ๆ รวมถึงตัวสร้างหรือ destructor) และรหัสของคุณเรียกใช้ฟังก์ชั่นในสิ่งนี้หมายความว่าอย่างไร
การจากตัวอย่างของคุณถ้าคุณเรียกว่าinitialize_vector()
คอมไพเลอร์ที่มีการตัดสินใจว่าคุณหมายจริงๆจะเรียกการดำเนินงานที่พบในหรือการดำเนินการที่พบในBase
Derived
มีสองวิธีในการตัดสินใจ:
- ครั้งแรกคือการตัดสินใจว่าเพราะคุณเรียกจากชนิดคุณหมายถึงการดำเนินการใน
Base
Base
- ที่สองคือการตัดสินใจว่าเพราะประเภทรันไทม์ของค่าที่เก็บไว้ใน
Base
ค่าที่พิมพ์อาจจะเป็นBase
หรือDerived
ว่าการตัดสินใจว่าจะโทรทำจะต้องทำที่รันไทม์เมื่อเรียก (แต่ละครั้งมันถูกเรียก)
คอมไพเลอร์ ณ จุดนี้สับสนทั้งสองตัวเลือกนั้นใช้ได้อย่างเท่าเทียมกัน นี่คือเมื่อvirtual
เข้ามาในการผสม เมื่อคำหลักนี้นำเสนอคอมไพเลอร์เลือกตัวเลือก 2 ชะลอการตัดสินใจระหว่างการใช้งานที่เป็นไปได้ทั้งหมดจนกระทั่งรหัสกำลังทำงานด้วยค่าจริง เมื่อคำหลักนี้ขาดคอมไพเลอร์เลือกตัวเลือก 1 เพราะนั่นเป็นพฤติกรรมปกติ
คอมไพเลอร์อาจยังคงเลือกตัวเลือก 1 ในกรณีของการเรียกฟังก์ชันเสมือน แต่ถ้ามันสามารถพิสูจน์ได้ว่าเป็นเช่นนี้เสมอ
ตัวสร้างและ Destructors
เหตุใดเราไม่ระบุตัวสร้างเสมือน
คอมไพเลอร์จะเลือกระหว่างการใช้งานที่เหมือนกันของ Constructor สำหรับDerived
และDerived2
? มันค่อนข้างเรียบง่าย แต่ทำไม่ได้ ไม่มีค่าที่มีอยู่ล่วงหน้าซึ่งคอมไพเลอร์สามารถเรียนรู้สิ่งที่ตั้งใจจริง ไม่มีค่าที่มีอยู่ล่วงหน้าเพราะนั่นคืองานของตัวสร้าง
เหตุใดเราจึงต้องระบุตัวทำลายเสมือน
คอมไพเลอร์จะเลือกระหว่างการนำไปใช้กับBase
และDerived
อย่างไร พวกเขาเป็นเพียงการเรียกใช้ฟังก์ชันดังนั้นพฤติกรรมการเรียกใช้ฟังก์ชันจึงเกิดขึ้น คอมไพเลอร์จะตัดสินใจผูกโดยตรงกับBase
destructor โดยไม่คำนึงถึงชนิดของค่ารันไทม์
ในคอมไพเลอร์จำนวนมากหากสิ่งที่ได้รับไม่ได้ประกาศข้อมูลสมาชิกใด ๆ หรือสืบทอดมาจากประเภทอื่น ๆ พฤติกรรมใน~Base()
จะเหมาะสม แต่ก็ไม่รับประกัน มันจะทำงานได้อย่างหมดจดโดยเหตุการณ์ที่เกิดขึ้นเหมือนยืนอยู่หน้าเครื่องพ่นสารเคมีที่ยังไม่ได้ติดไฟ คุณสบายดีซักพักหนึ่ง
วิธีที่ถูกต้องในการประกาศพื้นฐานหรือประเภทอินเตอร์เฟสใด ๆ ใน C ++ คือการประกาศ destructor เสมือนจริงเพื่อให้ destructor ที่ถูกต้องนั้นถูกเรียกสำหรับอินสแตนซ์ที่กำหนดของลำดับชั้นชนิดนั้น ๆ สิ่งนี้ทำให้ฟังก์ชั่นที่มีความรู้มากที่สุดของอินสแตนซ์สามารถทำความสะอาดอินสแตนซ์นั้นได้อย่างถูกต้อง
~derived()
ผู้ได้รับมอบหมายนั้นเป็นผู้ทำลายล้างของ vec หรือคุณกำลังสมมติว่าunique_ptr<base> pt
จะรู้ว่าตัวทำลายที่ได้รับมา หากไม่มีวิธีเสมือนสิ่งนี้จะไม่เป็นเช่นนั้น ในขณะที่ unique_ptr อาจได้รับฟังก์ชั่นการลบที่เป็นพารามิเตอร์แม่แบบโดยไม่ต้องมีตัวแทน runtime และคุณลักษณะนั้นไม่มีประโยชน์สำหรับรหัสนี้