เมื่อเราสร้างคลาสที่สืบทอดมาจากคลาสนามธรรมและเมื่อเราใช้คลาสนามธรรมที่สืบทอดมาทำไมเราต้องใช้คีย์เวิร์ด override?
"ทำไม?" คำถามเช่นนี้อาจตอบยากเพราะมันคลุมเครือ ฉันจะสมมติว่าคำถามของคุณคือ "มีข้อโต้แย้งอะไรบ้างในระหว่างการออกแบบภาษาเพื่อโต้แย้งสำหรับตำแหน่งที่จำเป็นต้องใช้overrideคำหลัก"
มาเริ่มกันที่ขั้นตอนก่อนกัน ในบางภาษาพูดว่า Java วิธีการเป็นเสมือนโดยค่าเริ่มต้นและแทนที่โดยอัตโนมัติ นักออกแบบของ C # ทราบเรื่องนี้และคิดว่าเป็นข้อบกพร่องเล็กน้อยใน Java C # ไม่ใช่ "Java ที่เอาชิ้นส่วนที่โง่ออกมา" อย่างที่บางคนกล่าว แต่ผู้ออกแบบ C # กระตือรือร้นที่จะเรียนรู้จากประเด็นการออกแบบที่เป็นปัญหาของ C, C ++ และ Java และไม่ทำซ้ำใน C #
นักออกแบบ C # ถือว่าการเอาชนะเป็นแหล่งที่เป็นไปได้ของข้อบกพร่อง; ท้ายที่สุดมันเป็นวิธีที่จะเปลี่ยนพฤติกรรมของรหัสที่มีอยู่ทดสอบและที่เป็นอันตราย การเอาชนะไม่ใช่สิ่งที่ควรทำอย่างตั้งใจหรือไม่ตั้งใจ ควรได้รับการออกแบบโดยคนที่คิดอย่างหนักเกี่ยวกับเรื่องนี้ นั่นเป็นสาเหตุที่วิธีการไม่ใช่ค่าเริ่มต้นเสมือนจริงและทำไมคุณต้องบอกว่าคุณกำลังเอาชนะวิธีการ
นั่นคือเหตุผลพื้นฐาน ตอนนี้เราสามารถไปสู่การใช้เหตุผลขั้นสูงมากขึ้น
คำตอบของ StriplingWarrior ให้การตัดแรกที่ดีที่ทำให้การโต้แย้งขั้นสูงมากขึ้น ผู้เขียนคลาสที่ได้รับอาจจะไม่รู้เกี่ยวกับระดับฐานอาจจะตั้งใจที่จะทำให้วิธีการใหม่และเราไม่ควรอนุญาตให้ผู้ใช้เพื่อแทนที่โดยไม่ได้ตั้งใจ
แม้ว่าประเด็นนี้จะสมเหตุสมผล แต่มีหลายข้อโต้แย้งเช่น:
- ผู้เขียนคลาสที่ได้รับมีหน้าที่รับผิดชอบในการรู้ทุกอย่างเกี่ยวกับคลาสพื้นฐาน! พวกเขากำลังใช้รหัสนั้นอีกครั้งและพวกเขาควรทำการตรวจสอบสถานะให้เข้าใจรหัสนั้นอย่างถี่ถ้วนก่อนนำมาใช้อีกครั้ง
- ในสถานการณ์เฉพาะของคุณวิธีเสมือนเป็นนามธรรม มันจะเป็นข้อผิดพลาดที่จะไม่แทนที่มันและดังนั้นจึงไม่น่าที่ผู้เขียนจะสร้างการใช้งานโดยไม่ได้ตั้งใจ
จากนั้นเราจะสร้างข้อโต้แย้งที่ก้าวหน้ายิ่งขึ้นในประเด็นนี้ ผู้เขียนของคลาสที่ได้รับภายใต้สถานการณ์ใดสามารถแก้ตัวโดยไม่รู้ว่าคลาสพื้นฐานทำอะไร? ดีพิจารณาสถานการณ์นี้:
- ผู้เขียนชั้นฐานทำให้ชั้นฐานนามธรรม
- ผู้เขียนคลาสที่ได้รับในทีมอื่นทำให้คลาส D ที่ได้รับมามีเมธอด M
- ผู้เขียนคลาสฐานตระหนักดีว่าทีมที่ขยายคลาส B นั้นจะต้องจัดหาเมธอด M เสมอดังนั้นผู้เขียนคลาสฐานจะเพิ่มเมธอด abstract M
- เมื่อคลาส D ถูกคอมไพล์ใหม่จะเกิดอะไรขึ้น
สิ่งที่เราต้องการให้เกิดขึ้นเป็นผู้เขียนของ D จะได้รับแจ้งว่ามีบางอย่างที่เกี่ยวข้องมีการเปลี่ยนแปลง สิ่งที่เกี่ยวข้องที่มีการเปลี่ยนแปลงคือตอนนี้ M เป็นข้อกำหนดและการใช้งานของพวกเขาจะต้องมากเกินไป DM อาจจำเป็นต้องเปลี่ยนพฤติกรรมเมื่อเรารู้ว่าสามารถเรียกได้จากคลาสฐาน สิ่งที่ถูกต้องคืออย่าพูดอย่างเงียบ ๆ ว่า "โอ้มี DM แล้วขยาย BM" สิ่งที่ถูกต้องสำหรับคอมไพเลอร์ที่ต้องทำคือล้มเหลวและพูดว่า "เฮ้, ผู้เขียน D, ตรวจสอบสมมติฐานของคุณซึ่งไม่สามารถใช้งานได้อีกต่อไปและแก้ไขรหัสของคุณหากจำเป็น"
ในตัวอย่างของคุณสมมติว่าoverrideเป็นตัวเลือกที่เปิดSayHelloเพราะมันเป็นวิธีที่เป็นนามธรรม มีความเป็นไปได้สองประการ: (1) ผู้เขียนโค้ดตั้งใจที่จะลบล้างวิธีนามธรรมหรือ (2) วิธีการแทนที่นั้นจะถูกลบล้างโดยไม่ได้ตั้งใจเพราะมีคนอื่นเปลี่ยนคลาสพื้นฐาน เราไม่สามารถบอกความเป็นไปได้เหล่านี้ออกจากกันถ้าoverrideเป็นตัวเลือก
แต่ถ้าoverrideถูกต้องแล้วเราสามารถบอกความแตกต่างสามสถานการณ์ หากมีข้อผิดพลาดที่เป็นไปได้ในรหัสนั้นoverrideจะหายไป หากมีการจงใจเอาชนะแล้วoverrideเป็นปัจจุบัน และถ้าหากจงใจไม่ล้มล้างก็newจะปรากฏขึ้น การออกแบบของ C # ทำให้เราสามารถสร้างความแตกต่างที่ลึกซึ้งเหล่านี้ได้
โปรดจำไว้รวบรวมข้อผิดพลาดการรายงานต้องอ่านใจของนักพัฒนา ; คอมไพเลอร์จะต้องอนุมานจากรหัสผิดสิ่งที่รหัสที่ถูกต้องที่ผู้เขียนมีอยู่ในใจและให้ข้อผิดพลาดที่ชี้ให้พวกเขาไปในทิศทางที่ถูกต้อง เบาะแสเพิ่มเติมที่เราสามารถทำให้นักพัฒนาทิ้งไว้ในโค้ดเกี่ยวกับสิ่งที่พวกเขากำลังคิดอยู่ยิ่งงานที่คอมไพเลอร์สามารถทำได้ดีกว่าในการรายงานข้อผิดพลาดดังนั้นยิ่งคุณสามารถค้นหาและแก้ไขข้อบกพร่องได้เร็วขึ้นเท่านั้น
แต่โดยทั่วไป, C # ได้รับการออกแบบสำหรับโลกที่เปลี่ยนแปลงรหัส คุณลักษณะที่ยอดเยี่ยมมากมายของ C # ซึ่งปรากฏว่า "แปลก" นั้นมีอยู่จริงเพราะพวกเขาแจ้งให้ผู้พัฒนาทราบเมื่อข้อสันนิษฐานที่เคยใช้นั้นไม่ถูกต้องเพราะชั้นฐานเปลี่ยนไป คลาสของบั๊กนี้เรียกว่า "ความล้มเหลวของคลาสพื้นฐานที่เปราะ" และ C # มีจำนวนการบรรเทาที่น่าสนใจสำหรับคลาสความล้มเหลวนี้