อ่าน 4 นาที
การโอเวอร์โหลดฟังก์ชัน
ในบางภาษา โปรแกรม การโอเวอร์โหลดฟังก์ชัน หรือ การโอเวอร์โหลดเมธอด คือความสามารถในการสร้าง ฟังก์ชัน หลายฟังก์ชัน ที่มีชื่อเดียวกันแต่มีการใช้งานที่แตกต่างกัน...
การโอเวอร์โหลดฟังก์ชัน
| โพลีมอร์ฟิซึม |
|---|
| โพลีมอร์ฟิซึมเฉพาะกิจ |
| โพลีมอร์ฟิซึมแบบพาราเมตริก |
| การกำหนดประเภทย่อย |
ในบางภาษาโปรแกรมการโอเวอร์โหลดฟังก์ชันหรือการโอเวอร์โหลดเมธอดคือความสามารถในการสร้างฟังก์ชัน หลายฟังก์ชัน ที่มีชื่อเดียวกันแต่มีการใช้งานที่แตกต่างกัน การเรียกใช้ฟังก์ชันที่โอเวอร์โหลดจะเรียกใช้การใช้งานเฉพาะของฟังก์ชันนั้นที่เหมาะสมกับบริบทของการเรียกใช้ ทำให้การเรียกใช้ฟังก์ชันเพียงครั้งเดียวสามารถทำงานที่แตกต่างกันได้ขึ้นอยู่กับบริบท
คำจำกัดความพื้นฐาน
ตัวอย่างเช่น`doTask()`และ`doTask(object o)` เป็นฟังก์ชันโอเวอร์โหลด ในการเรียกใช้ ฟังก์ชันหลังจะต้องส่งอ็อบเจ็กต์เป็นพารามิเตอร์ในขณะที่ฟังก์ชันแรกไม่ต้องการพารามิเตอร์ และถูกเรียกใช้โดยที่ช่องพารามิเตอร์ว่างเปล่า ข้อผิดพลาดที่พบบ่อยคือการกำหนดค่าเริ่มต้นให้กับอ็อบเจ็กต์ในฟังก์ชันที่สอง ซึ่งจะส่งผลให้เกิด ข้อผิดพลาด ในการเรียกใช้ที่ไม่ชัดเจนเนื่องจากคอมไพเลอร์จะไม่ทราบว่าควรใช้วิธีใดในสองวิธีนี้
อีกตัวอย่างหนึ่งคือ ฟังก์ชัน Print(object o)ที่ทำงานแตกต่างกันไปตามว่าเป็นการพิมพ์ข้อความหรือรูปภาพ ฟังก์ชันทั้งสองนี้สามารถโอเวอร์โหลดได้เป็นPrint(text_object T); Print(image_object P)หากเราเขียนฟังก์ชัน print ที่โอเวอร์โหลดสำหรับวัตถุทุกชิ้น โปรแกรมของเราจะ "พิมพ์" ได้โดยที่เราไม่ต้องกังวลเกี่ยวกับชนิดของวัตถุและการเรียกใช้ฟังก์ชันที่ถูกต้องอีกต่อไป การเรียกใช้จะเป็นPrint(something)เสมอ
ภาษาที่รองรับการโอเวอร์โหลด
ภาษาโปรแกรมที่รองรับการโอเวอร์โหลดฟังก์ชัน ได้แก่ แต่ไม่จำกัดเพียง:
- อาดา
- เอเพ็กซ์
- ซี++
- ซี#
- โคลจูร์[ 1 ]
- คริสตัล[ 2 ]
- ดี
- เดลฟี[ 3 ]
- ยาอายุวัฒนะ
- สวิฟต์
- ฟอร์ทราน
- โคทลิน[ 4 ]
- Java [ 5 ]
- จูเลีย
- นิม[ 6 ]
- PostgreSQL [ 7 ]และPL/SQL [ 8 ]
- สกาล่า
- ไทป์สคริปต์
- วิชวลเบสิก (.NET)
- ภาษาวูลฟรัม
ภาษาโปรแกรม ที่ ไม่รองรับการโอเวอร์โหลดฟังก์ชัน ได้แก่C , Python , RustและZig
กฎในการโอเวอร์โหลดฟังก์ชัน
- มีการใช้ชื่อฟังก์ชันเดียวกันสำหรับคำจำกัดความฟังก์ชันมากกว่าหนึ่งรายการในโมดูล คลาส หรือเนมสเปซเดียวกัน
- ฟังก์ชันจะต้องมีลายเซ็นประเภท ที่แตกต่างกัน กล่าวคือ แตกต่างกันในจำนวนหรือประเภทของพารามิเตอร์อย่างเป็นทางการ (เช่นใน C++) หรือเพิ่มเติมในประเภทการส่งคืน (เช่นใน Ada) [ 9 ]
การโอเวอร์โหลดฟังก์ชันมักเกี่ยวข้องกับภาษาการเขียนโปรแกรมแบบกำหนดประเภทคงที่ ซึ่งบังคับใช้ การตรวจสอบประเภทในการเรียกฟังก์ชันฟังก์ชันโอเวอร์โหลดคือชุดของฟังก์ชันที่แตกต่างกันซึ่งสามารถเรียกได้ด้วยชื่อเดียวกัน สำหรับการเรียกใดๆ คอมไพเลอร์จะพิจารณาว่าควรใช้ฟังก์ชันโอเวอร์โหลดใดและแก้ไขสิ่งนี้ในเวลาคอมไพล์นี่เป็นความจริงสำหรับภาษาการเขียนโปรแกรมเช่น Java [ 10 ]
การโอเวอร์โหลดฟังก์ชันแตกต่างจากรูปแบบโพลีมอร์ฟิซึม บางประเภท ที่การเลือกเกิดขึ้นในขณะรันไทม์ เช่น ผ่านฟังก์ชันเสมือนแทนที่จะเลือกแบบสแตติก
ตัวอย่าง: การโอเวอร์โหลดฟังก์ชันในภาษา C++
import std ;// ปริมาตรของลูกบาศก์int volume ( int s ) { return s * s * s ; }// ปริมาตรของทรงกระบอกdouble volume ( double r , int h ) { return std :: numbers :: pi * r * r * static_cast < double > ( h ); }// ปริมาตรของทรงสี่เหลี่ยมมุมฉาก (ปริซึมสี่เหลี่ยมผืนผ้า) long volume ( long l , int b , int h ) { return l * b * h ; }int main () { std :: println ( "{}" , volume ( 10 )); std :: println ( "{}" , volume ( 2.5 , 8 )); std :: println ( "{}" , volume ( 100l , 75 , 15 )); }ในตัวอย่างข้างต้น ปริมาตรของแต่ละส่วนประกอบจะถูกคำนวณโดยใช้ฟังก์ชัน "ปริมาตร" หนึ่งในสามฟังก์ชัน โดยการเลือกใช้จะขึ้นอยู่กับจำนวนและประเภทของพารามิเตอร์จริงที่แตกต่างกัน
การโอเวอร์โหลดคอนสตรัคเตอร์
คอนสตรัคเตอร์ซึ่งใช้ในการสร้างอินสแตนซ์ของวัตถุ อาจถูกโอเวอร์โหลดได้ในภาษาการเขียนโปรแกรมเชิงวัตถุ บาง ภาษา เนื่องจากในหลายภาษา ชื่อของคอนสตรัคเตอร์ถูกกำหนดไว้ล่วงหน้าโดยชื่อของคลาส จึงดูเหมือนว่าจะมีคอนสตรัคเตอร์ได้เพียงตัวเดียวเท่านั้น เมื่อใดก็ตามที่ต้องการคอนสตรัคเตอร์หลายตัว จะต้องนำไปใช้เป็นฟังก์ชันโอเวอร์โหลด ในC++คอนสตรัคเตอร์เริ่มต้น จะไม่รับพารามิเตอร์ใดๆ โดยจะสร้างอินสแตนซ์ของ สมาชิกวัตถุด้วยค่าเริ่มต้นที่เหมาะสม "ซึ่งโดยปกติจะเป็นศูนย์สำหรับฟิลด์ตัวเลขและสตริงว่างสำหรับฟิลด์สตริง" [ 11 ]ตัวอย่างเช่น คอนสตรัคเตอร์เริ่มต้นสำหรับวัตถุบิลร้านอาหารที่เขียนด้วย C++ อาจตั้งค่าทิปเป็น 15%:
บิล() : ทิป{ 0.15 }, รวม{ 0.0 } {}ข้อเสียของวิธีนี้คือต้องใช้สองขั้นตอนในการเปลี่ยนค่าของอ็อบเจ็กต์ Bill ที่สร้างขึ้น ต่อไปนี้แสดงวิธีการสร้างและเปลี่ยนค่าภายในโปรแกรมหลัก:
บิลค่าอาหาร; ทิป= 0.10 ; ยอดรวม= 4.00 ;โดยการโอเวอร์โหลดคอนสตรัคเตอร์ เราสามารถส่งค่าทิปและยอดรวมเป็นพารามิเตอร์ในการสร้างอ็อบเจ็กต์ได้ ภาพนี้แสดงคอนสตรัคเตอร์ที่โอเวอร์โหลดแล้วซึ่งมีพารามิเตอร์สองตัว คอนสตรัคเตอร์ที่โอเวอร์โหลดนี้ถูกวางไว้ในคลาสเช่นเดียวกับคอนสตรัคเตอร์ดั้งเดิมที่เราใช้ก่อนหน้านี้ ว่าจะใช้ตัวใดนั้นขึ้นอยู่กับจำนวนพารามิเตอร์ที่ให้มาเมื่อสร้างอ็อบเจ็กต์ Bill ใหม่ (ไม่มี หรือสองตัว):
บิล( ทิปสองเท่า, ยอดรวมสองเท่า) : ทิป{ ทิป}, ยอดรวม{ ยอดรวม} {}ตอนนี้ฟังก์ชันที่สร้างอ็อบเจ็กต์ Bill ใหม่สามารถส่งค่าสองค่าเข้าไปในคอนสตรัคเตอร์และกำหนดค่าให้กับสมาชิกข้อมูลได้ในขั้นตอนเดียว ตัวอย่างต่อไปนี้แสดงการสร้างและการกำหนดค่า:
บิลค่ากาแฟ( 0.10 , 4.00 );วิธีนี้สามารถช่วยเพิ่มประสิทธิภาพของโปรแกรมและลดความยาวของโค้ดได้
อีกเหตุผลหนึ่งสำหรับการโอเวอร์โหลดคอนสตรัคเตอร์คือการบังคับให้สมาชิกข้อมูลต้องมีค่าบังคับ ในกรณีนี้ คอนสตรัคเตอร์เริ่มต้นจะถูกประกาศเป็น private หรือ protected (หรือควรลบออกไปเลยตั้งแต่C++11 ) เพื่อไม่ให้สามารถเข้าถึงได้จากภายนอก สำหรับบิลข้างต้น total อาจเป็นพารามิเตอร์เดียวของคอนสตรัคเตอร์ เนื่องจากบิลไม่มีค่าเริ่มต้นที่เหมาะสมสำหรับ total ในขณะที่ tip มีค่าเริ่มต้นเป็น 0.15
ภาวะแทรกซ้อน
มีสองประเด็นที่เกี่ยวข้องและทำให้การโอเวอร์โหลดฟังก์ชันซับซ้อนขึ้น ได้แก่การปกปิดชื่อ (เนื่องจากขอบเขต ) และการแปลงประเภทโดยปริยาย
หากมีการประกาศฟังก์ชันในขอบเขตหนึ่ง และจากนั้นมีการประกาศฟังก์ชันอื่นที่มีชื่อเดียวกันในขอบเขตภายใน จะมีพฤติกรรมการโอเวอร์โหลดที่เป็นไปได้ตามธรรมชาติสองแบบ: การประกาศภายในจะซ่อนการประกาศภายนอก (โดยไม่คำนึงถึงลายเซ็น) หรือทั้งการประกาศภายในและการประกาศภายนอกจะรวมอยู่ในการโอเวอร์โหลด โดยการประกาศภายในจะซ่อนการประกาศภายนอกก็ต่อเมื่อลายเซ็นตรงกันเท่านั้น ใน C++ จะใช้แบบแรก: "ใน C++ ไม่มีการโอเวอร์โหลดข้ามขอบเขต" [ 12 ]ดังนั้น เพื่อให้ได้ชุดโอเวอร์โหลดที่มีฟังก์ชันที่ประกาศในขอบเขตที่แตกต่างกัน จำเป็นต้องนำเข้าฟังก์ชันจากขอบเขตภายนอกไปยังขอบเขตภายในอย่างชัดเจนด้วยusingคำหลัก
การแปลงประเภทโดยปริยายทำให้การโอเวอร์โหลดฟังก์ชันซับซ้อนขึ้น เพราะหากประเภทของพารามิเตอร์ไม่ตรงกับลายเซ็นของฟังก์ชันโอเวอร์โหลดตัวใดตัวหนึ่งอย่างแม่นยำ แต่สามารถตรงกันได้หลังจากแปลงประเภทแล้ว การแก้ไขปัญหาจะขึ้นอยู่กับว่าเลือกใช้การแปลงประเภทแบบใด
สิ่งเหล่านี้สามารถรวมกันได้ในลักษณะที่สับสน: การจับคู่ที่ไม่ตรงกันเป๊ะที่ประกาศไว้ในขอบเขตภายในสามารถบดบังการจับคู่ที่ตรงกันเป๊ะที่ประกาศไว้ในขอบเขตภายนอกได้ ตัวอย่างเช่น[ 12 ]
ตัวอย่างเช่น หากต้องการมีคลาสที่สืบทอดมาซึ่งมีฟังก์ชันโอเวอร์โหลดที่รับค่าเป็นdoubleหรือintโดยใช้ฟังก์ชันที่รับค่าเป็นintจากคลาสพื้นฐาน ในภาษา C++ จะต้องเขียนดังนี้:
คลาสBase { public : void fn ( int i ); };class Derived : public Base { public : using Base :: fn ; void fn ( double d ); };การไม่รวมusingผลลัพธ์ในintพารามิเตอร์ที่ส่งผ่านไปยังfnคลาสที่สืบทอดซึ่งถูกแปลงเป็นค่าทศนิยม และการจับคู่ฟังก์ชันในคลาสที่สืบทอด แทนที่จะเป็นในคลาสพื้นฐาน การรวมusingผลลัพธ์ในการโอเวอร์โหลดในคลาสที่สืบทอด และทำให้ตรงกับฟังก์ชันในคลาสพื้นฐาน
ข้อควรระวัง
หากเมธอดถูกออกแบบให้มีโอเวอร์โหลดมากเกินไป อาจทำให้ผู้พัฒนาแยกแยะได้ยากว่ากำลังเรียกใช้โอเวอร์โหลดใดโดยการอ่านโค้ดเพียงอย่างเดียว โดยเฉพาะอย่างยิ่งหากพารามิเตอร์บางตัวในโอเวอร์โหลดเป็นประเภทที่สืบทอดมาจากพารามิเตอร์อื่นๆ (เช่น "object") IDE สามารถทำการตรวจสอบโอเวอร์โหลดและแสดงผล (หรือนำทางไปยัง) โอเวอร์โหลดที่ถูกต้องได้
การโอเวอร์โหลดตามประเภทอาจขัดขวางการบำรุงรักษาโค้ดได้เช่นกัน โดยการอัปเดตโค้ดอาจทำให้คอมไพเลอร์เลือกโอเวอร์โหลดเมธอดโดยไม่ได้ตั้งใจ[ 13 ]
ดูเพิ่มเติม
- นามธรรม (วิทยาการคอมพิวเตอร์)
- ผู้สร้าง (วิทยาการคอมพิวเตอร์)
- อาร์กิวเมนต์เริ่มต้น
- การจัดส่งแบบไดนามิก
- รูปแบบวิธีการผลิต
- ลายเซ็นเมธอด
- เมธอดโอเวอร์ไรด์
- การเขียนโปรแกรมเชิงวัตถุ
- การโอเวอร์โหลดผู้ปฏิบัติงาน
การอ้างอิง
- ^ "Clojure - เรียนรู้ Clojure - ฟังก์ชัน" . clojure.org . สืบค้นเมื่อ2023-06-13 .
- ^ "เอกสารคริสตัล" . crystal-lang.org .
- ^ "Embarcadero Delphi" . embarcadero.com .
- ^ "ข้อกำหนดของภาษา Kotlin" . kotlinlang.org .
- ^ Bloch 2018 , หน้า 238-244, §บทที่ 8 ข้อ 52: กำจัดคำเตือนที่ไม่ได้ตรวจสอบ
- ^ "คู่มือการใช้งาน Nim" . nim-lang.org .
- ^ "37.6. การโอเวอร์โหลดฟังก์ชัน" . เอกสารประกอบ PostgreSQL . 2021-08-12 . สืบค้นเมื่อ2021-08-29 .
- ^ "คู่มือผู้ใช้และเอกสารอ้างอิง PL/SQL สำหรับฐานข้อมูล" . docs.oracle.com . สืบค้นเมื่อ2021-08-29 .
- ^วัตต์, เดวิด เอ.; ฟินด์เลย์, วิลเลียม (1 พฤษภาคม 2547). แนวคิดการออกแบบภาษาโปรแกรม . สำนักพิมพ์จอห์น ไวลีย์ แอนด์ ซันส์ อิงค์. หน้า 204–207 . ISBN 978-0-470-85320-7.
- ^ Bloch 2018 , หน้า 238-244, §บทที่ 8 ข้อ 52: ใช้การโอเวอร์โหลดอย่างรอบคอบ
- ^ Chan, Jamie (2017). เรียนรู้ C# ในหนึ่งวันและเรียนรู้ให้ดี (ฉบับปรับปรุง). หน้า 82. ISBN 978-1518800276.
- ^ a b Stroustrup, Bjarne . "ทำไมการโอเวอร์โหลดจึงใช้ไม่ได้กับคลาสที่สืบทอดมา?" .
- ^ Bracha, Gilad (3 กันยายน 2552). "ภาระเกินพิกัดของระบบ"ห้อง 101.
ลิงก์ภายนอก
- Meyer, Bertrand (ตุลาคม 2001). "Overloading vs Object Technology" (PDF)คอลัมน์ Eiffel วารสารการ เขียนโปรแกรมเชิงวัตถุ14 (4). 101 Communications LLC: 3– 7 สืบค้นเมื่อ27 สิงหาคม 2020