หมายเหตุนี้อธิบายถึงงานประจำเกี่ยวกับ MFC ที่สนับสนุนวัตถุ c ++แบบถาวรและรูปแบบของข้อมูลวัตถุเมื่อนั้นถูกเก็บในแฟ้ม นี้ใช้เฉพาะกับชั้นกับแมโคDECLARE_SERIALและIMPLEMENT_SERIAL?
ปัญหา
MFC ใช้งานสำหรับข้อมูลแบบถาวรอาศัยรูปแบบไบนารีที่กระทัดรัดสำหรับบันทึกข้อมูลหลายวัตถุในส่วนเดียวติดกันของแฟ้ม รูปแบบไบนารีที่นี้แสดงโครงสร้างสำหรับวิธีการจัดเก็บข้อมูล แต่ก็เป็นฟังก์ชันของสมาชิกของSerializeของวัตถุที่ให้ข้อมูลจริงที่บันทึกไว้ โดยวัตถุ?
MFC แก้ปัญหา structuring โดยใช้คลาสCArchive วัตถุCArchiveให้มีสร้างบริบทสำหรับเก็บรักษาที่กินเวลาจากเวลาเก็บถาวรจนกว่าสมาชิกฟังก์ชันCArchive::Closeจะเรียกว่า อย่างชัดเจน โดยโปรแกรมเมอร์ที่ หรือโดยปริยาย โดย destructor ที่เมื่อประกอบด้วยการCArchiveขอบเขตคือ exited?
หมายเหตุนี้อธิบายการใช้งานสมาชิกCArchive ReadObjectและWriteObject ReadObjectและWriteObjectจะไม่เรียกโดยตรงแต่ จะถูกใช้ โดยตัวคลาสเฉพาะชนิดเซฟแทรกและแยกดำเนินสร้างขึ้นโดยอัตโนมัติ โดยแมโคDECLARE_SERIALและIMPLEMENT_SERIAL?
คลา CMyObject: CObject สาธารณะ
{
nbsp DECLARE_SERIAL(CMyObject)
};
IMPLEMENT_SERIAL (CMyObj, CObject, 1)
/ / ตัวอย่างการใช้งาน (ar เป็นแบบ CArchive &)
CMyObject * pObj
CArchive & ar
ar << pObj / / เรียกใช้ arWriteObject(pObj)
ar >> pObj / / เรียกใช้ arReadObject(RUNTIME_CLASS(CObj))
หมายเหตุนี้อธิบายรหัสที่อยู่ในแฟ้มต้นฉบับ MFC ARCOBJCPP การใช้งานCArchiveหลักสามารถพบได้ใน ARCCORECPP?
การบันทึกวัตถุไปยังเก็บ (CArchive::WriteObject)
สมาชิกฟังก์ชันCArchive::WriteObjectเขียนข้อมูลหัวข้อที่ใช้เพื่อการสร้างวัตถุใหม่ ข้อมูลนี้ประกอบด้วยสองส่วน: ชนิดของวัตถุและสถานะของวัตถุ ฟังก์ชันนี้สมาชิกมีหน้าที่ในการดูแลข้อมูลเฉพาะของวัตถุกำลังเขียน เพื่อที่สำเนาเดียวเท่านั้นคือบันทึก โดยไม่คำนึงถึงจำนวนของตัวชี้ไปยังวัตถุนั้น (รวมทั้งตัวชี้แบบวงกลม)?
บันทึก (แทรก) และการคืนค่าวัตถุ (extracting) อาศัยค่าหลาย "รายการคง เหล่านี้เป็นค่าที่จะถูกเก็บเป็นเลขฐานสอง และให้ข้อมูลที่สำคัญไปยังเก็บถาวร (หมายเหตุ 16 บิตปริมาณที่บ่งชี้ว่า คำนำหน้า "w"):
| แท็ก | คำอธิบาย |
| wNullTag | ใช้สำหรับตัวชี้วัตถุ NULL (0)? |
| wNewClassTag | บ่งชี้ว่า คลาสอธิบายที่ตามหลังใหม่เพื่อ context(-1) การเก็บถาวรนี้? |
| wOldClassTag | บ่งชี้ว่า คลาสของวัตถุถูกอ่านได้ถูกมองเห็นได้ในบริบทนี้ (0x8000)? |
เมื่อเก็บวัตถุ การเก็บถาวรรักษาแบบCMapPtrToPtr (ในm_pStoreMap) ซึ่งเป็นการแมปจากวัตถุเก็บไว้กับตัวระบุแบบ 32 บิตแบบถาวร (PID) มีกำหนดหมายเลขผลิตภัณฑ์ทุกวัตถุที่ไม่ซ้ำกันและชื่อทุกคลาสที่ไม่ซ้ำกันที่บันทึกไว้ในบริบทของการเก็บถาวร PIDs เหล่านี้ถูกนำเสนอออกตามลำดับเริ่มต้นที่ 1 สิ่งสำคัญคือให้หมายเหตุว่า PIDs เหล่านี้ได้มีความสำคัญอยู่ภายนอกขอบเขตของการเก็บถาวร และ จะไม่ให้ สับสนกับการบันทึกหมายเลขหรือรายการรหัสประจำตัวอื่น ๆ โดยเฉพาะอย่างยิ่ง?
เริ่มต้น ด้วย MFC เวอร์ชัน 4.0 คลาCArchiveได้ถูกขยายเพื่อสนับสนุนการเก็บถาวรที่มีขนาดใหญ่มาก ในรุ่นก่อนหน้า หมายเลขผลิตภัณฑ์ได้ปริมาณแบบ 16 บิต จำกัดการเก็บถาวรไปยังวัตถุ (32766) 0x7FFE PIDs ตอนนี้มี 32 บิต แต่พวกเขาจะเขียนเป็น 16 บิตยกเว้นว่าพวกเขาจะมีขนาดใหญ่กว่า 0x7FFE PIDs ขนาดใหญ่จะถูกเขียนเป็น 0x7FFF ตาม ด้วยหมายเลขผลิตภัณฑ์ 32 บิต เทคนิคนี้รักษาความเข้ากันได้แบบย้อนหลังของแฟ้ม?
เมื่อทำการร้องขอการบันทึกวัตถุฐานข้อมูล (มักจะผ่านตัวดำเนินการแทรกส่วนกลาง), การตรวจสอบทำสำหรับตัวชี้ NULL CObject ถ้าตัวชี้เป็น NULL, wNullTag ถูกแทรกเข้าไปในกระแสข้อมูลเก็บถาวร?
หากเรามีตัวชี้วัตถุจริงที่สามารถเป็นแบบอนุกรม (ชั้นคือ ชั้นDECLARE_SERIAL ), เราจากนั้นตรวจสอบm_pStoreMapดูถ้าวัตถุนั้นถูกบันทึกไว้แล้ว ถ้ามี เราใส่หมายเลขผลิตภัณฑ์ 32 บิตที่เกี่ยวข้องกับวัตถุ?
ถ้าวัตถุไม่ถูกบันทึกก่อน ไม่มีโอกาสที่สองที่เราต้องใช้เวลาเข้าบัญชี: ทั้งวัตถุและชนิดแน่นอน (นั่นคือ คลาส) ของวัตถุยังใหม่กับบริบทนี้เก็บถาวร หรือวัตถุมีชนิดแน่นอนที่ดูแล้ว การตรวจสอบว่า ชนิดได้ถูกเห็นเราสอบถามm_pStoreMapสำหรับCRuntimeClassวัตถุที่ตรงกับวัตถุCRuntimeClassเกี่ยวข้องกับวัตถุเรากำลังบันทึก ถ้าเราได้เห็นชั้นนี้ก่อนWriteObjectแทรกแท็กที่เป็น OR'ing bit-wise wOldClassTag และดัชนีนี้ ถ้าการCRuntimeClassใหม่กับบริบทนี้เก็บถาวร แล้วWriteObjectกำหนดหมายเลขผลิตภัณฑ์ใหม่ที่คลาส และใส่ลงในเก็บถาวร นำหน้า ด้วยค่าwNewClassTag?
ตัวบอกลักษณะที่สำหรับคลาสนี้ถูกแทรกลงในเก็บถาวรที่ใช้ฟังก์ชันCRuntimeClassสมาชิกเก็บแล้ว CRuntimeClass::Storeแทรกหมายเลขเค้าร่างของคลา (ดูด้านล่าง) และชื่อข้อความ ASCII ของชั้นนั้น หมายเหตุที่ ใช้ชื่อข้อความ ASCII ไม่รับประกันหลัก ๆ ของการเก็บถาวรทั้งโปรแกรมประยุกต์ ดังนั้น จะขอแนะนำให้การติดแท็กให้กับแฟ้มข้อมูลของคุณเพื่อป้องกันไม่ให้เกิดความเสียหาย ต่อการแทรกข้อมูลคลาส เก็บถาวรของวางวัตถุที่เป็นm_pStoreMapแล้ว เรียกฟังก์ชันสมาชิกSerializeเพื่อใส่ข้อมูลเฉพาะคลาลงในเก็บถาวร วางวัตถุลงในm_pStoreMapก่อนการเรียกSerializeป้องกันหลายสำเนาของวัตถุกำลังจะถูกบันทึกไปยังเก็บ?
เมื่อกลับไปยังผู้เรียกต้น (โดยปกติแล้วรากของเครือข่ายของวัตถุ), คุณจำเป็นต้องปิดการเก็บถาวร ถ้าการดำเนินการอื่นCFileจะทำได้ ต้องถูกเรียกฟังก์ชันสมาชิกCArchiveล้าง ความล้มเหลวในการดำเนินการดังกล่าวจะส่งผลให้ในเก็บถาวรที่เสียหาย?
หมายเหตุnbsp ใช้งานนี้กำหนดไว้ในฮาร์ดจำกัดของดัชนี 0x3FFFFFFE ต่อบริบทการเก็บถาวร หมายเลขนี้แสดงถึงจำนวนสูงสุดของวัตถุที่ไม่ซ้ำกันและเรียนที่สามารถบันทึกได้ในเก็บถาวรที่เดียว แต่หมายเหตุเดียวดิสก์แฟ้มสามารถมีจำนวนไม่จำกัดของบริบทการเก็บถาวร(&N)?
กำลังโหลดวัตถุจากเก็บ (CArchive::ReadObject)
กำลังโหลดวัตถุ (extracting) ใช้ฟังก์ชันCArchive::ReadObjectสมาชิก และ การเสวนาของWriteObject เรียกเป็นกับWriteObject, ReadObjectไม่ว่าโดยตรง โดยใช้รหัสผู้ใช้ รหัสผู้ใช้ควรเรียกตัวดำเนินการแยกชนิดเซฟซึ่งเรียกใช้ReadObjectกับการคาดCRuntimeClass นี้ insures ความสมบูรณ์ชนิดของการดำเนินการแยก?
เริ่มตั้งแต่การใช้งานWriteObjectกำหนดให้เพิ่มขึ้น PIDs, 1 กำหนด (0 ไว้ล่วงหน้าเป็นวัตถุ NULL), ReadObjectใช้งานสามารถใช้อาร์เรย์ในการรักษาสถานะของเก็บแบบถาวรได้ เมื่อหมายเลขผลิตภัณฑ์จะอ่านจากเก็บ หากหมายเลขผลิตภัณฑ์เป็นมากกว่าขอบเขตบนปัจจุบันของการm_pLoadArrayแล้วReadObjectรู้ว่า วัตถุใหม่ (หรือคำอธิบายของคลาส) ตาม?
เค้าร่างตัวเลข
เลข schema ซึ่งถูกกำหนดให้กับคลาเมื่อเจอของคลาIMPLEMENT_SERIAL "รุ่น" ของคลาสใช้งานได้ Schema อ้างอิงถึงการใช้งานชั้น ทำไม่ให้จำนวนครั้งที่ วัตถุที่กำหนดไว้แบบถาวร (มักเรียกว่ารุ่นวัตถุ)?
ถ้าคุณต้องการรักษาใช้งานแตกต่างกันหลายของชั้นเรียนเดียวกันตลอดเวลา เพิ่มจำนวนตัวนับ schema ขณะที่คุณแก้ไขการใช้งานฟังก์ชันของวัตถุSerializeสมาชิกจะช่วยให้คุณเขียนโค้ดที่สามารถโหลดวัตถุโดยใช้ implementation.nbsp ในรุ่นเก่า(&N);
สมาชิกฟังก์ชันCArchive::ReadObjectจะโยนCArchiveExceptionเมื่อพบหมายเลขในเก็บแบบถาวรซึ่งแตกต่างจากคำอธิบายของคลาสในหน่วยความจำจำนวนเค้าร่าง เค้าร่าง ไม่ง่ายที่จะกู้คืนจากนี้ยกเว้น?
คุณสามารถใช้VERSIONABLE_SCHEMAหรือมีกับรุ่นของ schema ของคุณเพื่อให้ข้อยกเว้นนี้จากเก่า ๆ ถูก โดยใช้VERSIONABLE_SCHEMAโค้ดของคุณสามารถทำการดำเนินการที่เหมาะสมในหน้าที่Serializeโดยการตรวจสอบค่าส่งกลับจากCArchive::GetObjectSchema?
โทรศัพท์ซีเรียลไลซ์ได้โดยตรง
มีหลายกรณีค่าใช้จ่ายในแบบแผนเก็บวัตถุทั่วไปของWriteObjectและReadObjectไม่จำเป็น หรือไม่ที่ต้องการ เป็นกรณีนี้โดยทั่วไปของกับ serializing ข้อมูลลงในแบบCDocument ในกรณีนี้ฟังก์ชันSerializeสมาชิกของCDocumentเรียกว่าตรง ไม่ มีการแยก หรือแทรกตัวดำเนินการ เนื้อหาของเอกสารอาจจะใช้ชุดรูปแบบเก็บถาวรทั่วไปของวัตถุ?
โทรSerializeโดยตรงมีข้อดีและข้อเสียดังต่อไปนี้:
เนื่องจากSerializeเรียกว่าในเอกสารของคุณโดยตรง ไม่มักจะเป็นไปได้สำหรับวัตถุที่ย่อยของเอกสารเก็บถาวรข้อมูลอ้างอิงเอกสารหลักของพวกเขา วัตถุเหล่านี้ต้องถูกกำหนดให้ตัวชี้ไปยังเอกสารของคอนเทนเนอร์อย่างชัดเจน หรือคุณต้องใช้ฟังก์ชันCArchive::MapObjectเพื่อแมปCDocumentชี้ไปยังหมายเลขผลิตภัณฑ์ก่อนที่ตัวชี้หลังเหล่านี้จะถูกเก็บถาวร?
ดังที่กล่าวไว้ข้างต้น คุณเข้าควรรหัสข้อมูลรุ่นและคลาสตัวเองเมื่อเรียก Serialize โดยตรง การอนุญาตให้คุณเปลี่ยนรูปแบบในขณะที่ยังคง รักษาความเข้ากันได้แบบย้อนหลังกับแฟ้มเก่าในภายหลัง ฟังก์ชันCArchive::SerializeClassRefสามารถเรียกอย่างชัดเจน ก่อนโดยตรงกับ serializing วัตถุ หรือ ก่อนการเรียกคลาสพื้นฐาน?
หมายเหตุด้านเทคนิคตามหมายเลข|nbsp หมายเหตุด้านเทคนิคตามประเภท(&N)