อ่าน 5 นาที
การคัดลอกวัตถุ
ใน การเขียนโปรแกรมเชิงวัตถุ การ คัดลอกวัตถุ คือ การสร้าง สำเนาของ วัตถุ ที่มีอยู่ ซึ่งเป็นหน่วยข้อมูลในการเขียนโปรแกรมเชิงวัตถุ วัตถุที่ได้เรียกว่า สำเนาวัตถุ หรือเรียกง่ายๆ ว่า...
การคัดลอกวัตถุ
ในการเขียนโปรแกรมเชิงวัตถุการคัดลอกวัตถุคือการสร้างสำเนาของวัตถุ ที่มีอยู่ ซึ่งเป็นหน่วยข้อมูลในการเขียนโปรแกรมเชิงวัตถุ วัตถุที่ได้เรียกว่าสำเนาวัตถุหรือเรียกง่ายๆ ว่าสำเนาของวัตถุต้นฉบับ การคัดลอกเป็นพื้นฐานแต่ก็มีรายละเอียดปลีกย่อยและอาจมีค่าใช้จ่ายสูง มีหลายวิธีในการคัดลอกวัตถุ วิธีที่พบมากที่สุดคือการใช้ตัวสร้างสำเนาหรือการโคลนการคัดลอกทำขึ้นส่วนใหญ่เพื่อให้สามารถแก้ไขหรือย้ายสำเนา หรือเก็บรักษาค่าปัจจุบันไว้ หากไม่จำเป็นต้องทำสิ่งใดสิ่งหนึ่ง การอ้างอิงถึงข้อมูลต้นฉบับก็เพียงพอและมีประสิทธิภาพมากกว่า เนื่องจากไม่มีการคัดลอกเกิดขึ้น
โดย ทั่วไปแล้ว อ็อบเจ็กต์จะเก็บข้อมูลแบบผสมในกรณีง่ายๆ การคัดลอกสามารถทำได้โดยการสร้างอ็อบเจ็กต์ใหม่ที่ยังไม่ได้กำหนดค่าเริ่มต้น และคัดลอกฟิลด์ทั้งหมด ( แอตทริบิวต์ ) จากอ็อบเจ็กต์เดิม แต่ในกรณีที่ซับซ้อนกว่านั้น วิธีนี้อาจไม่ได้ผลลัพธ์ที่ต้องการ
วิธีการคัดลอก
เป้าหมายการออกแบบของวัตถุส่วนใหญ่คือการทำให้ดูเหมือนว่าทำมาจากชิ้นส่วนเดียวขนาดใหญ่ แม้ว่าส่วนใหญ่จะไม่ใช่เช่นนั้นก็ตาม เนื่องจากวัตถุประกอบด้วยชิ้นส่วนที่แตกต่างกันหลายส่วน การลอกเลียนแบบจึงไม่ใช่เรื่องง่าย มีหลายกลยุทธ์ที่ใช้ในการแก้ปัญหานี้
พิจารณาวัตถุ A ซึ่งมีฟิลด์ x i (กล่าวให้ชัดเจนยิ่งขึ้น พิจารณาว่า A เป็นสตริงและ x iเป็นอาร์เรย์ของอักขระ) มีกลยุทธ์ที่แตกต่างกันสำหรับการสร้างสำเนาของ A ซึ่งเรียกว่าการคัดลอกแบบตื้นและการคัดลอกแบบลึก ภาษาโปรแกรมหลายภาษาอนุญาตให้คัดลอกแบบทั่วไปโดยใช้กลยุทธ์ใดกลยุทธ์หนึ่งหรือทั้งสองกลยุทธ์ โดยกำหนดการดำเนินการ คัดลอกเพียงครั้งเดียวหรือการดำเนินการคัดลอกแบบตื้นและ การ คัดลอกแบบลึก แยกกัน [ 1 ]โปรดทราบว่าการคัดลอกแบบตื้นยิ่งกว่าคือการใช้การอ้างอิงไปยังวัตถุ A ที่มีอยู่ ซึ่งในกรณีนี้จะไม่มีวัตถุใหม่ มีเพียงการอ้างอิงใหม่เท่านั้น
คำศัพท์การคัดลอกแบบตื้นและการคัดลอกแบบลึกมีมาตั้งแต่Smalltalk -80 [ 2 ]ความแตกต่างเดียวกันนี้ใช้ได้กับการเปรียบเทียบวัตถุเพื่อความเท่าเทียมกัน: โดยพื้นฐานแล้วมีความแตกต่างระหว่างเอกลักษณ์ (วัตถุเดียวกัน) และความเท่าเทียมกัน (ค่าเดียวกัน) ซึ่งสอดคล้องกับความเท่าเทียมกันแบบตื้นและความเท่าเทียมกันแบบลึก (ระดับ 1) ของการอ้างอิงวัตถุสองรายการ แต่จากนั้นก็มีความแตกต่างเพิ่มเติมว่าความเท่าเทียมกันหมายถึงการเปรียบเทียบเฉพาะฟิลด์ของวัตถุที่เกี่ยวข้องหรือการเข้าถึงฟิลด์บางส่วนหรือทั้งหมดและเปรียบเทียบค่าของฟิลด์เหล่านั้น (เช่น รายการเชื่อมโยงสองรายการเท่ากันหรือไม่หากมีโหนดเดียวกัน หรือหากมีค่าเดียวกัน?)
สำเนาตื้นๆ
วิธีหนึ่งในการคัดลอกวัตถุคือการคัดลอกแบบตื้นในกรณีนี้ วัตถุใหม่ B จะถูกสร้างขึ้นและค่าฟิลด์ของ A จะถูกคัดลอกไปยัง B [ 3 ] [ 4 ] [ 5 ]วิธีนี้เรียกอีกอย่างว่าการคัดลอกแบบฟิลด์ต่อฟิลด์ [ 6 ] [ 7 ] [ 8 ]การคัดลอกแบบฟิลด์ต่อฟิลด์หรือ การคัด ลอกฟิลด์[ 9 ]หากค่าฟิลด์เป็นการอ้างอิงถึงวัตถุ (เช่น ที่อยู่หน่วยความจำ ) มันจะคัดลอกการอ้างอิง ดังนั้นจึงอ้างอิงถึงวัตถุเดียวกันกับ ที่ A อ้างอิง และหากค่าฟิลด์เป็นชนิดข้อมูลพื้นฐาน มันจะคัดลอกค่าของชนิดข้อมูลพื้นฐานนั้น ในภาษาที่ไม่มีชนิดข้อมูลพื้นฐาน (ที่ทุกอย่างเป็นวัตถุ) ฟิลด์ทั้งหมดของสำเนา B จะเป็นการอ้างอิงถึงวัตถุเดียวกันกับฟิลด์ของ A เดิม วัตถุที่อ้างอิงจึงถูกใช้ร่วมกันดังนั้นหากวัตถุใดวัตถุหนึ่งถูกแก้ไข (จาก A หรือ B) การเปลี่ยนแปลงจะปรากฏให้เห็นในอีกวัตถุหนึ่ง การคัดลอกแบบตื้นนั้นง่ายและโดยทั่วไปแล้วมีราคาถูก เนื่องจากโดยปกติแล้วสามารถทำได้โดยการคัดลอกบิตอย่างแม่นยำเท่านั้น
สำเนาเชิงลึก
อีกทางเลือกหนึ่งคือการคัดลอกแบบลึก ซึ่งหมายความว่าฟิลด์ต่างๆ จะถูกยกเลิกการอ้างอิง: แทนที่จะคัดลอกการอ้างอิงไปยังวัตถุต่างๆ จะมีการสร้างสำเนาใหม่ของวัตถุสำหรับวัตถุที่ถูกอ้างอิงทั้งหมด และการอ้างอิงถึงสำเนาใหม่เหล่านี้จะถูกวางไว้ใน B การแก้ไขเนื้อหาในภายหลังจะยังคงเป็นเอกลักษณ์เฉพาะของ A หรือ B เนื่องจากเนื้อหาไม่ได้ถูกแชร์
การผสมผสาน
ในกรณีที่ซับซ้อนกว่านั้น ฟิลด์บางฟิลด์ในสำเนาควรมีค่าร่วมกันกับวัตถุต้นฉบับ (เช่นเดียวกับการคัดลอกแบบตื้น) ซึ่งสอดคล้องกับความสัมพันธ์แบบ "การเชื่อมโยง" ฟิลด์บางฟิลด์ควรมีสำเนา (เช่นเดียวกับการคัดลอกแบบลึก) ซึ่งสอดคล้องกับความสัมพันธ์แบบ "การรวมกลุ่ม" ในกรณีเหล่านี้ โดยทั่วไปแล้วจำเป็นต้องมีการใช้งานการคัดลอกแบบกำหนดเอง ปัญหาและวิธีแก้ปัญหานี้มีมาตั้งแต่ Smalltalk-80 [ 10 ]หรืออีกทางหนึ่ง สามารถทำเครื่องหมายฟิลด์ว่าต้องการการคัดลอกแบบตื้นหรือการคัดลอกแบบลึก และสร้างการดำเนินการคัดลอกโดยอัตโนมัติ (เช่นเดียวกับการดำเนินการเปรียบเทียบ) [ 1 ]อย่างไรก็ตาม สิ่งนี้ไม่ได้ถูกนำไปใช้ในภาษาเชิงวัตถุส่วนใหญ่ แม้ว่าจะมีการสนับสนุนบางส่วนใน Eiffel ก็ตาม[ 1 ]
การดำเนินการ
ภาษาโปรแกรมเชิงวัตถุ เกือบทั้งหมดมีวิธีการคัดลอกวัตถุ เนื่องจากภาษาโปรแกรมส่วนใหญ่ไม่ได้จัดเตรียมวัตถุส่วนใหญ่ไว้ให้ โปรแกรมเมอร์จึงต้องกำหนดวิธีการคัดลอกวัตถุเอง เช่นเดียวกับการกำหนดว่าวัตถุสองชิ้นนั้นเหมือนกันหรือเปรียบเทียบกันได้หรือไม่ ภาษาโปรแกรมหลายภาษามีพฤติกรรมเริ่มต้นบางอย่างให้ใช้งาน
วิธีการแก้ปัญหาการคัดลอกนั้นแตกต่างกันไปในแต่ละภาษา และขึ้นอยู่กับแนวคิดเกี่ยวกับวัตถุที่ภาษานั้นมี
คัดลอกแบบง่ายๆ
การคัดลอกแบบเลซี่ (Lazy Copy) เป็นการนำการคัดลอกแบบดีพ (Deep Copy) มาใช้ ในขั้นตอนการคัดลอกวัตถุครั้งแรก จะใช้การคัดลอกแบบตื้น (Shallow Copy) ซึ่งรวดเร็วกว่า และใช้ตัวนับเพื่อติดตามจำนวนวัตถุที่ใช้ข้อมูลร่วมกัน เมื่อโปรแกรมต้องการแก้ไขวัตถุ ก็สามารถตรวจสอบได้ว่าข้อมูลนั้นถูกใช้ร่วมกันหรือไม่ (โดยการตรวจสอบตัวนับ) และสามารถทำการคัดลอกแบบดีพได้หากจำเป็น
การคัดลอกแบบ Lazy Copy มองจากภายนอกเหมือนกับการคัดลอกแบบ Deep Copy แต่ใช้ประโยชน์จากความเร็วของการคัดลอกแบบ Shallow Copy เมื่อใดก็ตามที่เป็นไปได้ ข้อเสียคือค่าใช้จ่ายพื้นฐานค่อนข้างสูงแต่คงที่เนื่องจากตัวนับ นอกจากนี้ ในบางสถานการณ์การอ้างอิงแบบวนซ้ำอาจทำให้เกิดปัญหาได้
การคัดลอกแบบไม่ละเอียด (Lazy copy) มีความเกี่ยวข้องกับลิขสิทธิ์แบบเขียนทับ (Copy-on-write )
ในภาษา C++การคัดลอกแบบเลซี่จะเกิดขึ้นโดยค่าเริ่มต้นเมื่อเรียกใช้คอน สตรัค เตอร์ การคัดลอก
ในภาษาจาวา
ต่อไปนี้เป็นตัวอย่างสำหรับภาษาเชิงวัตถุที่ใช้กันอย่างแพร่หลายภาษาหนึ่ง นั่นคือJavaซึ่งน่าจะครอบคลุมเกือบทุกวิธีที่ภาษาเชิงวัตถุสามารถใช้แก้ปัญหานี้ได้
ต่างจากใน C++ อ็อบเจ็กต์ใน Java จะถูกเข้าถึงโดยอ้อมผ่านการอ้างอิง เสมอ อ็อบเจ็กต์จะไม่ถูกสร้างขึ้นโดยปริยาย แต่จะถูกส่งผ่านหรือกำหนดโดยตัวแปรอ้างอิงเสมอ (เมธอดใน Java จะส่งผ่านค่า เสมอ อย่างไรก็ตาม ค่าที่ส่งผ่านคือค่าของตัวแปรอ้างอิง) [ 11 ]เครื่องเสมือน Javaจัดการการเก็บขยะเพื่อให้วัตถุถูกทำความสะอาดหลังจากที่ไม่สามารถเข้าถึงได้อีกต่อไป ไม่มีวิธีอัตโนมัติในการคัดลอกวัตถุใด ๆ ใน Java
โดย ปกติแล้ว การคัดลอกจะดำเนินการโดยเมธอด clone()ของคลาส เมธอดนี้มักจะเรียกเมธอด clone() ของคลาสแม่เพื่อรับสำเนา จากนั้นจึงดำเนินการคัดลอกตามขั้นตอนที่กำหนดเอง ในที่สุด ขั้นตอนนี้จะไปถึงเมธอด clone() ของObjectคลาสที่อยู่บนสุด ซึ่งจะสร้างอินสแตนซ์ใหม่ของคลาสเดียวกันกับอ็อบเจ็กต์และคัดลอกฟิลด์ทั้งหมดไปยังอินสแตนซ์ใหม่ (การคัดลอกแบบตื้น) หากใช้วิธีนี้ คลาสจะต้องใช้งานCloneableอินเทอร์เฟซมาร์กเกอร์ มิฉะนั้นจะเกิด ข้อผิดพลาด "Clone Not Supported Exception" หลังจากได้รับสำเนาจากคลาสแม่แล้ว เมธอด clone() ของคลาสเองอาจให้ความสามารถในการคัดลอกที่กำหนดเอง เช่น การคัดลอกแบบลึก (เช่น ทำซ้ำโครงสร้างบางส่วนที่อ้างอิงโดยอ็อบเจ็กต์) หรือการกำหนด ID ที่ไม่ซ้ำกันให้กับอินสแตนซ์ใหม่
เมธอด clone() จะคืนค่าเป็นObject`true` แต่ผู้เขียนเมธอด clone สามารถเขียนประเภทของอ็อบเจ็กต์ที่ถูกโคลนแทนได้ เนื่องจาก Java รองรับประเภทการคืนค่าแบบ covariantข้อดีอย่างหนึ่งของการใช้ clone() คือ เนื่องจากเป็นเมธอดที่สามารถเขียนทับได้เราจึงสามารถเรียก clone() บนอ็อบเจ็กต์ใดก็ได้ และมันจะใช้เมธอด clone() ของคลาสของอ็อบเจ็กต์นั้น โดยที่โค้ดที่เรียกไม่จำเป็นต้องรู้ว่าคลาสนั้นคืออะไร (ซึ่งจำเป็นต้องรู้หากใช้คอนสตรัคเตอร์แบบคัดลอก)
ข้อเสียอย่างหนึ่งคือ บ่อยครั้งที่เราไม่สามารถเข้าถึงเมธอด clone() บนประเภทนามธรรมได้อินเทอร์เฟซและคลาสแบบนามธรรมส่วนใหญ่ใน Java ไม่ได้ระบุเมธอด clone() สาธารณะ ดังนั้น บ่อยครั้งวิธีเดียวที่จะใช้เมธอด clone() ได้ก็ต่อเมื่อทราบคลาสของวัตถุ ซึ่งขัดแย้งกับหลักการนามธรรมของการใช้ประเภทที่ทั่วไปที่สุดเท่าที่จะเป็นไปได้ ตัวอย่างเช่น หากเรามีตัวอ้างอิง List ใน Java เราจะไม่สามารถเรียกใช้ clone() บนตัวอ้างอิงนั้นได้ เพราะ List ไม่ได้ระบุเมธอด clone() สาธารณะ การใช้งาน List เช่น ArrayList และLinkedListโดยทั่วไปจะมีเมธอด clone() แต่การพกพาประเภทคลาสของวัตถุไปด้วยนั้นไม่สะดวกและขัดกับหลักการนามธรรมที่ดี
อีกวิธีหนึ่งในการคัดลอกอ็อบเจ็กต์ใน Java คือการทำให้เป็นอนุกรมผ่านทางSerializableอินเทอร์เฟซ วิธีนี้มักใช้เพื่อการคงอยู่ของข้อมูลและ วัตถุประสงค์ ของโปรโตคอลการสื่อสารแต่ก็สร้างสำเนาของอ็อบเจ็กต์ได้เช่นกัน และแตกต่างจากคำสั่ง clone ตรงที่สามารถสร้างสำเนาแบบลึก (deep copy) ที่จัดการกับกราฟของอ็อบเจ็กต์ที่มีการวนซ้ำได้อย่างราบรื่น โดยใช้ความพยายามจากโปรแกรมเมอร์น้อยที่สุด
ทั้งสองวิธีนี้มีปัญหาสำคัญอย่างหนึ่งคือคอนสตรัคเตอร์ไม่ได้ใช้สำหรับวัตถุที่คัดลอกด้วยโคลนหรือซีเรียลไลเซชัน ซึ่งอาจนำไปสู่บั๊กที่มีข้อมูลเริ่มต้นไม่ถูกต้อง ป้องกันการใช้finalฟิลด์สมาชิก และทำให้การบำรุงรักษาเป็นเรื่องยาก ยูทิลิตี้บางตัวพยายามแก้ไขปัญหาเหล่านี้โดยใช้การสะท้อนเพื่อคัดลอกวัตถุแบบลึก เช่น ไลบรารีการโคลนแบบลึก[ 12 ]
ในหอไอเฟล
อ็อบเจ็กต์รันไทม์ในEiffelสามารถเข้าถึงได้ทั้งทางอ้อมผ่านการอ้างอิงหรือในรูปแบบ ของอ็อบเจ็กต์ ที่ขยายใหญ่ขึ้นซึ่งฟิลด์ต่างๆ จะถูกฝังอยู่ภายในอ็อบเจ็กต์ที่ใช้งาน กล่าวคือ ฟิลด์ของอ็อบเจ็กต์จะถูกจัดเก็บไว้ภายนอกหรือภายในก็ได้
คลาส Eiffel ANYมีคุณสมบัติสำหรับการคัดลอกและโคลนวัตถุแบบตื้นและแบบลึก คลาส Eiffel ทั้งหมดสืบทอดมาจากคลาส Eiffel ANYดังนั้นคุณสมบัติเหล่านี้จึงมีอยู่ในทุกคลาส และสามารถใช้ได้ทั้งกับวัตถุอ้างอิงและวัตถุที่ขยายเพิ่มเติม
ฟังก์ชัน นี้copyจะทำการคัดลอกข้อมูลแบบตื้นๆ จากฟิลด์หนึ่งไปยังอีกฟิลด์หนึ่ง ในกรณีนี้จะไม่มีการสร้างวัตถุใหม่ หากyมีการคัดลอกไปxยัง แล้ว วัตถุเดียวกันที่ถูกอ้างอิงโดยyก่อนการใช้งานฟังก์ชันนี้copyก็จะยังคงถูกอ้างอิงโดยxหลังจากที่copyฟังก์ชันทำงานเสร็จสมบูรณ์
เพื่อสร้างวัตถุใหม่ที่เป็นสำเนาแบบตื้นของวัตถุเดิม จะใช้ yฟีเจอร์twinนี้ ในกรณีนี้ จะมีการสร้างวัตถุใหม่หนึ่งชิ้นที่มีฟิลด์เหมือนกับวัตถุเดิมทุกประการ
คุณสมบัตินี้twinอาศัยคุณสมบัติcopyซึ่งสามารถกำหนดใหม่ในคลาสย่อยของ ได้ANYหากจำเป็น ผลลัพธ์ของtwinเป็นประเภทที่ยึดโยงlike Currentอยู่
การคัดลอกแบบลึกและการสร้างแฝดแบบลึกสามารถทำได้โดยใช้คุณสมบัติ `deep copying` และ `deep twins` deep_copyซึ่งdeep_twinสืบทอดมาจากคลาส `class` ANYคุณสมบัติเหล่านี้มีศักยภาพในการสร้างวัตถุใหม่จำนวนมาก เนื่องจากมันจะทำสำเนาวัตถุทั้งหมดในโครงสร้างวัตถุทั้งหมด เนื่องจากมีการสร้างวัตถุสำเนาใหม่แทนที่จะคัดลอกการอ้างอิงไปยังวัตถุที่มีอยู่ การดำเนินการแบบลึกจึงมีแนวโน้มที่จะก่อให้เกิดปัญหาด้านประสิทธิภาพได้ง่ายกว่าการดำเนินการแบบตื้น
ในภาษาอื่นๆ
ในC#แทนที่จะใช้อินเทอร์เฟซ เราสามารถใช้เมธอดส่วนขยายICloneableแบบเจเนริก เพื่อสร้างสำเนาแบบลึกโดยใช้การสะท้อน (reflection) ซึ่งมีข้อดีสองประการ: ประการแรก ช่วยให้มีความยืดหยุ่นในการคัดลอกทุกอ็อบเจ็กต์โดยไม่ต้องระบุคุณสมบัติและตัวแปรที่จะคัดลอกแต่ละรายการด้วยตนเอง ประการที่สอง เนื่องจากชนิดเป็นแบบเจเนริก คอมไพเลอร์จึงตรวจสอบให้แน่ใจว่าอ็อบเจ็กต์ปลายทางและอ็อบเจ็กต์ต้นทางมีชนิดเดียวกัน
ในObjective-Cเมธอด `copy` copyและmutableCopy`copy` จะถูกสืบทอดโดยอ็อบเจ็กต์ทุกตัวและมีจุดประสงค์เพื่อทำการคัดลอก โดยเมธอด `copy` ใช้สำหรับสร้างชนิดข้อมูลที่เปลี่ยนแปลงได้ของอ็อบเจ็กต์ต้นฉบับ เมธอดเหล่านี้จะเรียกเมธอด `copy` copyWithZoneและmutableCopyWithZone`copy` ตามลำดับ เพื่อทำการคัดลอก อ็อบเจ็กต์จะต้องใช้งานcopyWithZoneเมธอด `copy` ที่เกี่ยวข้องจึงจะสามารถคัดลอกได้
ในภาษา OCamlฟังก์ชันไลบรารีOo.copyทำหน้าที่คัดลอกวัตถุแบบตื้น (shallow copying )
ในPythonโมดูล copy ของไลบรารีจะให้การคัดลอกแบบตื้นและการคัดลอกแบบลึกของวัตถุผ่าน ฟังก์ชัน copy()และdeepcopy()ตามลำดับ[ 13 ]โปรแกรมเมอร์อาจกำหนดเมธอดพิเศษ__copy__()และ__deepcopy__()ในวัตถุเพื่อจัดเตรียมการใช้งานการคัดลอกแบบกำหนดเอง
ในRubyวัตถุทั้งหมดสืบทอดเมธอดสองเมธอดสำหรับการทำสำเนาแบบตื้น ได้แก่cloneและdupเมธอดทั้งสองแตกต่างกันตรงที่cloneclone จะคัดลอกสถานะที่ปนเปื้อน สถานะแช่แข็ง และ เมธอด ซิงเกิลตัน ใดๆ ที่วัตถุอาจมี ในขณะที่dupdup จะคัดลอกเฉพาะสถานะที่ปนเปื้อนเท่านั้น การทำสำเนาแบบลึกสามารถทำได้โดยการดัมพ์และโหลดสตรีมไบต์ของวัตถุหรือการทำให้เป็นอนุกรมYAML [1]หรืออีกทางหนึ่ง คุณสามารถใช้ gem deep_dive เพื่อทำสำเนาแบบลึกที่ควบคุมได้ของกราฟวัตถุของคุณ[2]
ในRustโครงสร้างสามารถใช้cloneงานเมธอดโดยใช้Clonetrait ได้[ 14 ] [ 15 ]
ในภาษา Perlโครงสร้างแบบซ้อนกันจะถูกจัดเก็บโดยใช้การอ้างอิง ดังนั้นนักพัฒนาสามารถวนลูปผ่านโครงสร้างทั้งหมดและอ้างอิงข้อมูลใหม่ หรือใช้dclone()ฟังก์ชันจากโมดูลStorableก็ได้
ในVBAการกำหนดค่าให้กับตัวแปรประเภทหนึ่งObjectเรียกว่าการคัดลอกแบบตื้น (shallow copy) ส่วนการกำหนดค่าให้กับตัวแปรประเภทอื่นๆ (เช่น ตัวเลข สตริง ประเภทที่ผู้ใช้กำหนด และอาร์เรย์) เรียกว่าการคัดลอกแบบลึก (deep copy) ดังนั้นคำหลัก `value` Setสำหรับการกำหนดค่าจะบ่งบอกถึงการคัดลอกแบบตื้น และคำหลัก `value` (ซึ่งเป็นตัวเลือก) Letจะบ่งบอกถึงการคัดลอกแบบลึก ไม่มีเมธอดในตัวสำหรับการคัดลอกแบบลึกของอ็อบเจ็กต์ใน VBA
ดูเพิ่มเติม
หมายเหตุ
- ↑ เอบีซีโกรโกโน แอนด์ ซัคคิเนน 2000 .
- ^ Goldberg & Robson 1983 , หน้า 97–99. "มีสองวิธีในการสร้างสำเนาของวัตถุ ความแตกต่างอยู่ที่ว่าค่าของตัวแปรของวัตถุนั้นถูกคัดลอกหรือไม่ หากค่าไม่ถูกคัดลอก ค่าเหล่านั้นจะถูกใช้ร่วมกัน (
shallowCopy); หากค่าถูกคัดลอก ค่าเหล่านั้นจะไม่ถูกใช้ร่วมกัน (deepCopy)" - ^ "คำอธิบายการคัดลอกแบบตื้นและแบบลึกใน C++"เก็บถาวรจากต้นฉบับเมื่อ 2014-02-10 เรียกดูเมื่อ2013-04-10
- ^ "คำอธิบายการคัดลอกแบบตื้นและแบบลึกใน .NET "
- ^ "คำอธิบายความแตกต่างระหว่างการคัดลอกแบบตื้นและแบบลึกทั่วไป" . เก็บถาวรจากต้นฉบับเมื่อ 2016-03-04 . เรียกดูเมื่อ2013-04-10 .
- ^ Java หลัก: พื้นฐาน เล่ม 1หน้า 295
- ^ Effective Javaฉบับพิมพ์ครั้งที่สองหน้า 54
- ^ "การคัดลอกแบบทีละฟิลด์ที่ทำโดย Object.clone() คืออะไร? ", Stack Overflow
- ^ "Josh Bloch on Design: A Conversation with Effective Java Author, Josh Bloch", โดย Bill Venners, JavaWorld , 4 มกราคม 2545,หน้า 13
- ^ Goldberg & Robson 1983 , หน้า 97. "การใช้งานเริ่มต้นของ
copyคือshallowCopy. ในคลาสย่อยที่การคัดลอกต้องส่งผลให้เกิดการรวมกันพิเศษของตัวแปรที่ใช้ร่วมกันและตัวแปรที่ไม่ได้ใช้ร่วมกัน โดยปกติแล้วเมธอดที่เกี่ยวข้องกับ copy จะถูกเขียนใหม่ แทนที่จะเป็นเมธอดที่เกี่ยวข้องกับshallowCopyหรือdeepCopy." - ^ "การส่งข้อมูลไปยังเมธอดหรือคอนสตรัคเตอร์" สืบค้นเมื่อ 8 ตุลาคม 2556
- ^ไลบรารีการโคลนแบบลึกของ Java
- ^โมดูลการคัดลอก Python
- ^ "การโคลนใน std::clone - Rust" . doc.rust-lang.org . สืบค้นเมื่อ3 พฤศจิกายน 2025 .
- ^ "Clone - Rust By Example" . doc.rust-lang.org . สืบค้นเมื่อ3 พฤศจิกายน 2025 .
สรุปเนื้อหา
ข้อมูลสำคัญจากบทความ
ข้อมูลสำคัญเกี่ยวกับ การคัดลอกวัตถุ
ใน การเขียนโปรแกรมเชิงวัตถุ การ คัดลอกวัตถุ คือ การสร้าง สำเนาของ วัตถุ ที่มีอยู่ ซึ่งเป็นหน่วยข้อมูลในการเขียนโปรแกรมเชิงวัตถุ วัตถุที่ได้เรียกว่า สำเนาวัตถุ หรือเรียกง่ายๆ ว่า...
วิธีการคัดลอก
เป้าหมายการออกแบบของวัตถุส่วนใหญ่คือการทำให้ดูเหมือนว่าทำมาจากชิ้นส่วนเดียวขนาดใหญ่ แม้ว่าส่วนใหญ่จะไม่ใช่เช่นนั้นก็ตาม เนื่องจากวัตถุประกอบด้วยชิ้นส่วนที่แตกต่างกันหลายส่วน การลอกเลียนแบบจึงไม่ใช่เรื่องง่าย มีหลายกลยุทธ์ที่ใช้ในการแก้ปัญหานี้
สำเนาตื้นๆ
วิธีหนึ่งในการคัดลอกวัตถุคือ การคัดลอกแบบตื้น ในกรณีนี้ วัตถุใหม่ B จะ ถูกสร้างขึ้น และค่าฟิลด์ของ A จะถูกคัดลอกไปยัง B [ 3 ] [ 4 ] [ 5 ] วิธีนี้เรียกอีกอย่างว่า การคัดลอกแบบฟิลด์ต่อฟิลด์ [ 6 ] [ 7 ] [ 8 ] การคัดลอกแบบฟิลด์ต่อฟิลด์ หรือ การคัด ลอก ฟิลด์ [ 9 ]...
สำเนาเชิงลึก
อีกทางเลือกหนึ่งคือการคัดลอกแบบลึก ซึ่งหมายความว่าฟิลด์ต่างๆ จะถูกยกเลิกการอ้างอิง: แทนที่จะคัดลอกการอ้างอิงไปยังวัตถุต่างๆ จะมีการสร้างสำเนาใหม่ของวัตถุสำหรับวัตถุที่ถูกอ้างอิงทั้งหมด และการอ้างอิงถึงสำเนาใหม่เหล่านี้จะถูกวางไว้ใน B...


