TN002: Format danych obiektu trwałe

Uwaga ta opisuje procedury MFC, obsługujących trwałych obiektów C++ i format danych obiektu, gdy jest on przechowywany w pliku. Dotyczy to tylko klasy z makra DECLARE_SERIAL i IMPLEMENT_SERIAL.

Problem

Wykonania MFC trwałych danych zależy od zwartym formacie binarnym do zapisywania danych dla wielu obiektów w jednej części sąsiadujących pliku. To format binarny zawiera strukturę jak dane są przechowywane, ale jest on funkcji składowej Serialize obiektu, który zawiera rzeczywiste dane zapisane przez obiekt.

Urządzenie MFC rozwiązuje problem strukturalnych za pomocą klasy CArchive. Obiekt CArchive przewiduje, że kontekst dla trwałości, który trwa od czasu archiwum jest tworzony, dopóki wywołana funkcja Państwa CArchive::Close , albo jawnie przez programistę, albo pośrednio przez destruktor, gdy zakres zawierający CArchive jest zakończony.

Uwaga ta opisuje realizacji funkcji ReadObject i funkcji WriteObjectczłonków CArchive . Funkcji ReadObject i funkcji WriteObject nie są nazywane bezpośrednio natomiast są używane przez specyficzne dla klasy typ bezpiecznej wstawiania i ekstrakcji operatorów generowane automatycznie przez makra DECLARE_SERIAL i IMPLEMENT_SERIAL.

klasa CMyObject: CObject publicznych
{
 nbsp;  DECLARE_SERIAL(CMyObject)
};

IMPLEMENT_SERIAL (CMyObj, CObject, 1)

/ / przykład użycia (ar jest CArchive &)
CMyObject * pObj;
CArchive & czda;
Ar << pObj;        / / wywołuje cz.d.a.WriteObject(pObj)
Ar >> pObj;        / / wywołuje cz.d.a.ReadObject(RUNTIME_CLASS(CObj))

Uwaga ta opisuje kod znajduje się w pliku źródłowym MFC ARCOBJ.CPP. Implementacja CArchive można znaleźć w ARCCORE.CPP.

Zapisywanie obiektów do magazynu (CArchive::WriteObject)

Funkcję Państwa CArchive::WriteObject zapisuje nagłówek danych używaną do rekonstruowania obiektu. Dane te składa się z dwóch części: typu obiektu i stan obiektu. Ta funkcja Państwa także jest odpowiedzialny za utrzymywanie tożsamość obiektu są wypisywane, tak, że tylko pojedyncza kopia jest zapisywana, niezależnie od liczby wskaźników do tego obiektu (w tym wskaźników cykliczne).

Zapisywanie (Wkładanie) oraz Przywracanie obiektów (wydobywania) opiera się na kilku "manifestu stałych." Są to wartości, które są przechowywane w binarnym i dostarczają ważnych informacji dla archiwum (należy zauważyć, że prefiksu "w" oznacza ilości 16-bitowe):

Znacznik Opis
wNullTag Używane dla wskaźników obiektu NULL (0).
wNewClassTag Wskazuje, że opis klasy, który następuje jest nowa to context—(-1) archiwum.
wOldClassTag Wskazuje, że klasa obiektu odczytywanego została zaobserwowana w tym kontekście (0x8000).

Podczas przechowywania obiektów, archiwum utrzymuje CMapPtrToPtr ( m_pStoreMap) który jest mapowanie z obiektu przechowywane do 32-bitowego identyfikatora trwałe (PID). PID jest przypisywany do każdego unikatowego obiektu i co nazwa klasy unikatowe, zapisaną w kontekście archiwum. Te numery PID są wręcza kolejno począwszy od 1. Ważne jest, aby zauważyć, że te numery PID nie ma znaczenia poza zakresem archiwum i, w szczególności są nie powinien być mylony z numer rekordu lub inne elementy tożsamości.

Począwszy od wersji 4.0 MFC klasy CArchive została rozszerzona o bardzo dużej archiwa pomocy. W poprzednich wersjach PID był ilości 16-bitowe, ograniczając archiwum do obiektów (32766) 0x7FFE. Numery PID są obecnie 32-bitowe, ale oni są zapisywane jako 16-bitowe chyba, że są one większe niż 0x7FFE. Duże PID są zapisywane jako 0x7FFF następuje PID 32-bitowych. Ta technika utrzymuje zgodność ze starszymi wersjami plików.

Gdy żądanie do zapisania obiektu do archiwum (zazwyczaj za pomocą operatora globalnego wstawiania), sprawdzenie odbywa się za wskaźnik NULL CObject ; Jeżeli wskaźnik jest NULL, wNullTag jest wstawiany do strumienia archiwum.

Jeśli mamy wskaźnik prawdziwym przedmiotem, który jest w stanie poddany serializacji (klasa jest klasą DECLARE_SERIAL ), następnie sprawdzamy m_pStoreMap aby wyświetlić, jeśli obiekt został już zapisany. Jeśli tak, to mamy wstawić PID 32-bitowe, skojarzone z tym obiektem.

Jeśli obiekt nie został zapisany przed, istnieją dwie możliwości należy wziąć pod uwagę: zarówno obiekt, jak i dokładny typ (oznacza to, że klasa) obiektu są nowe do tego kontekstu archiwum lub obiekt znajduje się dokładny typ już widzieliśmy. Aby ustalić, jeśli typ zaobserwowano że możemy kwerendy m_pStoreMap dla obiektu CRuntimeClass , który pasuje do obiektu CRuntimeClass , skojarzone z obiektem, który możemy zapisywania. Jeśli widzieliśmy tej klasy przed funkcji WriteObject wstawia znacznik, który jest równe być wOldClassTag i indeks. Jeżeli CRuntimeClass jest nowy kontekst tego archiwum, następnie funkcji WriteObject przypisuje nowy identyfikator PID tej klasy i włóż ją do archiwum, poprzedzone wartością wNewClassTag.

Następnie dodaje się do archiwum przy użyciu funkcji członek CRuntimeClass magazynudeskryptora dla tej klasy. CRuntimeClass::Store wstawia numer schematu klasy (patrz poniżej) i nazwę tekstową ASCII klasy. Należy zauważyć, że używanie nazwy tekstu ASCII nie gwarantuje unikatowość archiwum między aplikacjami, zatem zaleca znaczników plików danych w celu zapobiegania korupcji. W następstwie wstawiania informacji klasy archiwum umieszcza obiekt do m_pStoreMap , a następnie wywołuje funkcję Państwa Serialize wstawić dane specyficzne dla klasy do archiwum. Umieszczenie obiektu w m_pStoreMap przed wywołaniem Serialize zapobiega wiele kopii tego samego obiektu są zapisane w magazynie.

Po powrocie do początkowej rozmówcy (zazwyczaj głównych sieci obiektów), jest ważna do ścisłej archiwum. Jeśli inne operacje CFile są dokonywane, musi zostać wywołana funkcja Państwa CArchive , opróżnić . Niespełnienie tego będzie skutkować uszkodzony archiwum.

Uwaga   Ta implementacja nakłada twardym limitem wskaźników 0x3FFFFFFE na kontekście archiwum. Liczba ta stanowi maksymalną liczbę unikatowych obiekty i klasy, które mogą być zapisywane w jednym, ale Uwaga, że pojedynczego dysku, plik może mieć nieograniczonej liczby kontekstów archiwum.

Ładowanie obiektów z magazynu (CArchive::ReadObject)

Ładowanie obiektów (wydobywania) używa funkcji członek CArchive::ReadObject i jest przeciwieństwem poprawności funkcji WriteObject. Jak z funkcji WriteObject, funkcji ReadObject nie jest wywoływana bezpośrednio przez użytkownika kod; kod użytkownika powinna wywołać operatora typ bezpiecznej ekstrakcji, które wymaga funkcji ReadObject z oczekiwanych CRuntimeClass. To już integralności typu operacji ekstraktu.

Ponieważ realizacji funkcji WriteObject przypisane rosnące PID, zaczynając od 1 (0 jest wstępnie jako obiekt NULL), realizacji funkcji ReadObject można używać tablicy do utrzymania stanu kontekście archiwum. Gdy PID jest odczytywany z magazynu, jeżeli numer PID jest większa niż bieżąca górną granicę m_pLoadArray, następnie funkcji ReadObject wie że nowego obiektu (lub opisowi klasy) następuje.

Numery schematu

Numer schematu, który jest przypisany do klasy po napotkaniu tej klasy IMPLEMENT_SERIAL , jest "wersja" Implementacja klasy. Schemat odnosi się do wprowadzenia w życie tej klasy, o ile razy dany obiekt dokonano trwałe (zwykle zwane wersji obiektu).

Jeśli użytkow&nik zamierza utrzymać kilka różnych implementacjach tej samej klasy w czasie, zwiększając schematu podczas poprawiania Twojego obiektu Serialize Członkowskie funkcji realizacji umożliwi to pisanie kodu, który można załadować obiekty przechowywane przy użyciu starszych wersji implementation.nbsp;

Funkcja Państwa CArchive::ReadObject wygeneruje CArchiveException , wówczas, gdy napotka numer schematu w Magazyn trwały, która różni się od schematu liczba opis klasy w pamięci. Nie jest łatwe do odzyskania z tego wyjątku.

Można użyć VERSIONABLE_SCHEMA lub miał posiadanej wersji schematu, aby zachować ten wyjątek nie wyjątek. Za pomocą VERSIONABLE_SCHEMA, kod może podjąć odpowiednie działania w jego funkcji Serialize sprawdzając wartość zwracany z CArchive::GetObjectSchema.

Wywołujący serializować bezpośrednio

Jest wiele przypadków, w których obciążenie systemu archiwizacji obiektu ogólnego funkcji WriteObject i funkcji ReadObject nie jest niezbędne lub pożądane. Jest to przypadek Szeregowanie danych do CDocument. W tym przypadku funkcja Członkowskie Serialize CDocument nazywa się bezpośrednio, nie z ekstraktu lub wstawić operatory. Zawartość dokumentu z kolei może użyć bardziej ogólny schemat archiwum obiektu.

Wywołanie Serialize bezpośrednio ma następujące zalety i wady:

Ponieważ Serialize nazywa się bezpośrednio w dokumencie, nie jest zwykle możliwe do podobiektów dokumentu do archiwum odniesienia do ich dokumentu nadrzędnego. Obiekty te muszą mieć wskaźnik do ich dokumencie kontenera jawnie lub aby mapowania wskaźnika CDocument PID przed tylnym wskaźniki te są archiwizowane, należy użyć funkcji CArchive::MapObject.

Jak wspomniano powyżej, powinny kodowania informacje o wersji i klasy samodzielnie podczas wywoływania Serialize bezpośrednio, umożliwiając później zmienić format zachowując zgodność ze starszymi wersjami z starsze pliki. Funkcję CArchive::SerializeClassRef można wywołać wyraźnie przed bezpośrednio szeregowania obiektu lub przed wywołaniem metody klasy podstawowej.

Uwagi techniczne przez liczbę |nbsp; Uwagi techniczne według kategorii

Index