สำเนาตื้นและสำเนาลึก
ในคลาส Circle ตัวอย่างของตัวสร้างการคัดลอกที่อธิบายไว้ในส่วนก่อนหน้า กลยุทธ์การคัดลอกจะสอดคล้องกับกลยุทธ์เริ่มต้นของระบบ นั่นคือ สมาชิกของออบเจ็กต์ต้นฉบับจะถูกคัดลอกไปยังสมาชิกที่สอดคล้องกันของออบเจ็กต์ใหม่ตามลำดับ กรณีนี้ทำไมเราถึงยัง อยากกำหนดเองล่ะ? เหตุผลก็คือ การเริ่มต้นสถานการณ์ทั้งหมดด้วยวิธีง่ายๆ นี้ย่อมนำไปสู่ปัญหาในสถานการณ์ที่แตกต่างกันอย่างหลีกเลี่ยงไม่ได้
ตัวอย่างเช่น ในคลาส Circle ในตอนนี้ หากมีการเพิ่ม สมาชิกพอยน์เตอร์ ลงในตัวแปรสมาชิกและหน่วยความจำจำเป็นต้องได้รับการจัดสรรแบบไดนามิกระหว่างการเริ่มต้น จะมีความเสี่ยงด้านความปลอดภัยอย่างมาก รหัสจะเป็นดังนี้:
/************************************//Des: โปรแกรมสนับสนุนการสอน C++//Author :Huang //CopyRight:www.dotcpp.com//Date:2017/8/26****************************** ** ******/#include<iostream>#include<Cstring>usingnamespacestd;#definePI3.1415classCircle{private:doubleR;char*str;public:Circle(doubleR,char*str);~Circle(); doublearea(); );doublegirth();};Circle::~Circle(){ลบ[]str;}Circle::Circle(doubleR,char*str){cout<<Constructor<<endl;this->R=R ;this ->str=newchar[strlen(str)+1];strcpy(this->str,str);cout<<this->R<<<<this->str<<endl;}doubleCircle::area () {returnPI*R*R;}doubleCircle::girth(){return2*PI*R;}intmain(){CircleA(5,NO.1Oldclass);CircleB(A);return0;}
ในการตรวจสอบในคลาส Circle เราได้เพิ่มสมาชิกตัวชี้และเริ่มต้นในตัวสร้างโดยไม่มีตัวสร้างการคัดลอกแบบกำหนดเอง จากนั้นในฟังก์ชันหลัก ประโยค Circle B(A) จะกำหนดวัตถุ A ให้กับวัตถุ B และเรียกตัวสร้างสำเนาเริ่มต้นที่สร้างขึ้น หลังจากรัน โปรแกรมจะรายงานข้อผิดพลาดดังที่แสดงด้านล่าง:
เหตุผลที่แท้จริงก็คือ ตัวสร้างการคัดลอกเริ่มต้นจะดำเนินการเฉพาะการกำหนดข้อมูล และไม่สามารถเปิดพื้นที่หน่วยความจำสำหรับพอยน์เตอร์ได้ ซึ่งเทียบเท่ากับโค้ด:
นี่->str=str;
โดยพื้นฐานแล้ว พอยน์เตอร์สองตัวชี้ไปที่พื้นที่ฮีป มันขัดกับความตั้งใจเดิมของเรา จากนั้นในตอนท้ายของโปรแกรม เมื่อวัตถุทั้งสองถูกรีไซเคิล ตัวทำลายล้างของมันเองจะถูกเรียกให้ปล่อยพื้นที่หน่วยความจำนี้ เนื่องจากจำเป็นต้องเรียกวัตถุทั้งสองสองครั้ง นั่นคือ ลบ สองครั้ง จึงเกิดข้อผิดพลาด!
ดังนั้นเมื่อมีประเภทตัวชี้ในชั้นเรียน การอาศัยวิธีการสร้างสำเนาเริ่มต้นจึงไม่สามารถตอบสนองความต้องการของเราได้อีกต่อไป จะต้องกำหนดตัวสร้างการคัดลอกเฉพาะ ซึ่งไม่เพียงแต่สามารถคัดลอกข้อมูล แต่ยังจัดสรรพื้นที่หน่วยความจำสำหรับสมาชิกด้วย เพื่อให้ได้สำเนาจริงหรือที่เรียกว่าสำเนาลึก นี่คือ ตัวสร้างสำเนาลึก
การใช้งานตัวสร้างสำเนาลึก:
#include<iostream>#include<Cstring>usingnamespacestd;#definePI3.1415classCircle{private:doubleR;char*str;public:Circle(doubleR,char*str);Circle(Circle&A);~Circle();doublerea(); doublegirth();};Circle::~Circle(){delete[]str;cout<<CallDestructor<<endl;}Circle::Circle(Circle&A){cout<<CopyConstructor<<endl;this->R=AR ;this->str=newchar[strlen(A.str)+1];strcpy(this->str,A.str);}วงกลม::วงกลม(doubleR,char*str){cout<<ตัวสร้าง<<endl ;this->R=R;this->str=newchar[strlen(str)+1];strcpy(this->str,str);}doubleCircle::area(){returnPI*R*R;}doubleCircle: :เส้นรอบวง(){return2*PI*R;}intmain(){CircleA(5,NO.1Oldclass);CircleB(A);return0;}
หลักการดำเนินการจะคล้ายกับตัวสร้างที่มีพารามิเตอร์ พื้นที่หน่วยความจำที่เพียงพอจะถูกเปิดก่อนที่จะมอบหมายให้ทำสำเนาให้เสร็จสมบูรณ์อย่างแท้จริง ซึ่งเรียกว่า "สำเนาลึก" โปรดเข้าใจและลองใช้บนคอมพิวเตอร์!