เมื่อเร็ว ๆ นี้ฉันเห็นชาวเน็ตถามบนอินเทอร์เน็ต: จะทราบได้อย่างไรว่าตัวชี้วัตถุพร้อมใช้งานหรือไม่? กล่าวอีกนัยหนึ่ง จะทราบได้อย่างไรว่าตัวชี้วัตถุชี้ไปยังอินสแตนซ์วัตถุที่ใช้งานได้จริงหรือไม่ จริงๆ แล้วเรื่องนี้ไม่น่าจะเป็นปัญหา เพราะสำหรับโปรแกรมเมอร์ เขาควรจะสามารถควบคุมโปรแกรมของเขาไม่ให้เข้าถึงตัวชี้ที่ไม่ถูกต้องได้ เพราะการสร้างและการทำลายอินสแตนซ์ออบเจ็กต์ทั้งหมดอยู่ภายใต้การควบคุมของเขา และแม้ว่าจะไม่มีวิธีโดยตรงในการพิจารณาว่าตัวชี้ออบเจ็กต์พร้อมใช้งานหรือไม่ ก็สามารถทำได้ด้วยวิธีทางอ้อมอื่นๆ (เช่น การใช้ตัวระบุบางตัว เป็นต้น) (เช่น เมื่อเราทำลายอินสแตนซ์ออบเจ็กต์ เราจะตั้งค่า ตัวชี้ของตัวชี้วัตถุเป็นศูนย์) แต่ถ้าเราละทิ้งสองประเด็นที่กล่าวมาข้างต้นและเพียงศึกษาว่ามีวิธีใดในการพิจารณาว่าตัวชี้วัตถุมีอยู่ใน Delphi หรือไม่ จะเกิดอะไรขึ้น?
ใน Object Pascal คลาสสามารถมีเมธอดได้สองประเภท วิธีหนึ่งเรียกว่าวิธีอ็อบเจ็กต์ (วิธีวัตถุ) และอีกวิธีคือวิธีคลาส (วิธีคลาส) วิธีการที่เรียกว่าวัตถุหมายความว่าคำจำกัดความของวิธีการนั้นมีไว้สำหรับวัตถุ (หรืออินสแตนซ์) ดังนั้นการเรียกวิธีการนั้นจะต้องขึ้นอยู่กับวัตถุ (หรืออินสแตนซ์) ตัวอย่างเช่น destructor Destroy ของคลาสคือวัตถุ method (จริงๆ แล้วเรามักจะใช้ method ส่วนใหญ่เป็น object method) วิธีการเรียนหมายถึงคำจำกัดความของวิธีการตามคลาสของวัตถุ ดังนั้นการเรียกวิธีการจึงไม่จำเป็นต้องขึ้นอยู่กับอินสแตนซ์ของวัตถุเฉพาะ เช่น ตัวสร้างการสร้างของชั้นเรียน สิ่งนี้มีแรงบันดาลใจสำหรับเรา การพิจารณาว่าตัวชี้วัตถุพร้อมใช้งานหรือไม่นั้นดูเหมือนว่าจะทำได้สำเร็จตามขั้นตอนต่อไปนี้ ขั้นแรก เราสามารถระบุได้ว่าตัวชี้อ็อบเจ็กต์เป็นศูนย์หรือไม่ ถ้าเป็นเช่นนั้น เราก็เสร็จแล้ว และไม่สามารถใช้งานได้แน่นอน ถ้าไม่ใช่ ให้ลองดำเนินการวิธีอ็อบเจ็กต์ของอ็อบเจ็กต์เพื่อดูว่ามีข้อยกเว้น เช่น การเข้าถึงหน่วยความจำที่ไม่ถูกต้องหรือไม่ ใช้เพื่อพิจารณาว่าวัตถุนั้นพร้อมใช้งานหรือไม่ ใช้รหัสต่อไปนี้เพื่อยืนยันความคิดของเรา:
var
วัตถุ: TObject;
เริ่ม
Obj := TObject.Create; //1. สร้างวัตถุ
Obj.Free; //2. ปล่อยวัตถุที่เพิ่งสร้างขึ้นและหน่วยความจำจะถูกรีไซเคิลในขณะนี้
ถ้า Obj = nil แล้ว //3. ตรวจสอบว่าตัวชี้ว่างเปล่าหรือไม่ (ขั้นตอนนี้มักจะไม่สำเร็จเนื่องจากวัตถุ
// ถูกปล่อยออกมา Delphi จะไม่ล้างตัวชี้วัตถุโดยอัตโนมัติ)
ShowMessage('ตัวชี้วัตถุไม่พร้อมใช้งาน')
อื่น
เริ่ม
พยายาม
ถ้า Obj.ClassType = TObject แล้ว //4 เรียกวิธีวัตถุของ TObject
ShowMessage('ประเภทวัตถุคือ TObject');
ยกเว้น
ShowMessage('ตัวชี้วัตถุไม่พร้อมใช้งาน')
จบ;
จบ;
จบ;
การดำเนินการตามโค้ดข้างต้น เราพบว่า Obj.ClassType ยังคงใช้งานได้ แม้ว่า Obj.Free จะถูกดำเนินการแล้วก็ตาม นี่แสดงให้เห็นว่าไม่ใช่ทุกวิธีของวัตถุจะต้องขึ้นอยู่กับอินสแตนซ์ของวัตถุจึงจะสามารถเข้าถึงได้ เหตุผลก็คือว่าวิธีวัตถุนี้ไม่จำเป็นต้องเข้าถึงหน่วยความจำที่ร้องขอโดยอินสแตนซ์ของวัตถุ ในแง่นี้ เมธอด TObject.ClassType ดูไม่เหมือนเมธอดอ็อบเจ็กต์จริง แต่มีลักษณะคล้ายกับเมธอดคลาส
จากการรันโค้ดข้างต้น เรายังพบว่าเมื่ออ็อบเจ็กต์รันเมธอด Free มันจะปล่อยหน่วยความจำทั้งหมดที่ใช้เมื่อถูกสร้างขึ้นเท่านั้น แต่จะไม่ส่งผลกระทบต่อค่าของตัวชี้อ็อบเจ็กต์เอง ตัวชี้วัตถุยังคงชี้ไปยังที่อยู่หน่วยความจำเดิม ในเวลาเดียวกัน เนื่องจากลักษณะพิเศษของการใช้วิธีการบางอย่างของวัตถุ (เช่น ClassType) แม้ว่าวัตถุจะถูกเผยแพร่ ผลลัพธ์ของการเรียกวิธีวัตถุยังคงถูกต้อง
โดยสรุป เราสามารถสรุปได้ว่า ตัวชี้วัตถุสามารถตัดสินได้ว่ามีอยู่หรือไม่นั้น ขึ้นอยู่กับว่าคลาสที่ตัวชี้วัตถุอยู่นั้นให้วิธีในการเข้าถึงหน่วยความจำอินสแตนซ์ของวัตถุหรือไม่ - วิธีนี้สามารถเป็นวิธีการได้เช่นกัน เป็นคุณสมบัติ แล้วสถานการณ์ตอนนี้โดยเฉพาะในแต่ละหมวดเป็นอย่างไร?
TObject คลาสนี้เป็นคลาสบรรพบุรุษของคลาสทั้งหมด ไม่มีทางที่จะตัดสินได้
TPersistent ซึ่งได้มาจาก TObject ไม่จำเป็นต้องใช้หน่วยความจำเพิ่มเติมเมื่อสร้างอินสแตนซ์ออบเจ็กต์ ดังนั้นจึงไม่มีทางตัดสินได้
TComponent ซึ่งได้มาจาก TPersistent ได้เพิ่มคุณสมบัติหลายอย่างที่ต้องใช้หน่วยความจำเพิ่มเติมเพื่อนำไปใช้ในการสร้างอินสแตนซ์ออบเจ็กต์ ดังนั้นในทางทฤษฎีแล้ว ถือว่าถูกตัดสิน รหัสมีดังนี้:
ฟังก์ชั่น ComponentExists (AComponent: TComponent): บูลีน;
เริ่ม
พยายาม
AComponent.Hasparent; //หมายเหตุ: ประโยคนี้อาจเป็น "AComponent.Tag;"
//หรือ "AComponent.Name"
ผลลัพธ์ := จริง;
ยกเว้น
ผลลัพธ์ := เท็จ;
จบ;
จบ;
ด้วยการเรียก ComponentExists เราสามารถรู้ได้ว่าตัวชี้วัตถุประเภท TComponent พร้อมใช้งานหรือไม่ โดยไม่คำนึงว่าตัวชี้วัตถุนั้นถูกเผยแพร่หรือตั้งค่าเป็นศูนย์หรือไม่
สำหรับคลาสอื่นๆ เช่น TControl, TWinControl หรือ TButton ฯลฯ ตราบใดที่คลาสเหล่านั้นได้มาจาก TComponent วิธีการตัดสินของ TComponent ยังคงนำไปใช้
มีคลาสที่ผู้ใช้กำหนดอื่น ๆ หากคลาสเหล่านั้นได้มาจากคลาสที่ไม่สามารถตัดสินได้โดยตรง (เช่น TObject และ TPersistent) แต่ไม่มีแอตทริบิวต์ที่ต้องใช้แอปพลิเคชันหน่วยความจำในระหว่างการสร้างอินสแตนซ์ มิฉะนั้นก็ไม่มีทางตัดสินได้ เป็นไปได้ ตามตัวอย่าง:
สมมติว่าเรามีคลาส Terson ที่กำหนดไว้ดังนี้:
TPerson = คลาส (TObject)
ส่วนตัว
FSex: TSex; // TSex คือเพศของประเภทการแจงนับ;
FFirstName: สตริง;
FLastName: สตริง;
-
สาธารณะ
ทรัพย์สิน เพศ: TSex อ่าน FSex เขียน FSex;
คุณสมบัติ ชื่อ: สตริง อ่าน FFirstName เขียน FFirstName;
คุณสมบัติ นามสกุล: สตริง อ่าน FLastName เขียน FLastName;
-
จบ;
จากนั้น สำหรับตัวชี้บุคคลประเภท TPerson คุณสามารถใช้โค้ดต่อไปนี้เพื่อตรวจสอบว่าตัวชี้พร้อมใช้งานหรือไม่:
พยายาม
คน.เพศ;
//หรือ Person.FirstName;
//หรือ Person.LastName;
ผลลัพธ์ := True; //ตัวชี้พร้อมใช้งาน
ยกเว้น
ผลลัพธ์ := False;//ตัวชี้ไม่พร้อมใช้งาน
จบ;
สิ่งที่เรากล่าวถึงข้างต้นเป็นเพียงความเป็นไปได้ทางเทคนิคเท่านั้น ประเด็นที่อยากเน้นย้ำคือถึงแม้จะมีวิธีทำที่ดีแต่ก็ไม่สนับสนุนให้ทำบ่อยๆ เนื่องจากโปรแกรมที่มีตรรกะที่เข้มงวดควรสามารถป้องกันการเข้าถึงพอยน์เตอร์ที่ไม่ถูกต้องได้
บทความเพิ่มเติม