Serialization: Serialize 가능한 클래스 만들기
MSDN에 Serializable클래스를 만드는 방법을 단계로 소개 하고 있다(클릭하면 사이트이동)
주요부분을 간단히 요약하면…..
1. Cobject에서 파생된 클래스를 만든다
2. Serialize 멤버 함수를 재정의 한다.
3. 클래스에 DECLARE_SERIAL 매크로를 선언 한다(“.h”파일).
4. 구현 파일에(.cpp)에 IMPLEMENT_SERIAL 매크로를 지정한다.
head 파일
1 2 3 4 5 6 7 8 9 10 11 12 13 | class CPerson : public CObject { public : DECLARE_SERIAL( CPerson ) // empty constructor is necessary CPerson(); virtual ~CPerson(); CString m_name; WORD m_number; void Serialize( CArchive& archive ); }; |
Serialize 멤버 함수를 재정의 하려면
- 기본 클래스 버전을 호출 합니다. Serialize 개체의 상속 된 부분이 serialize 될 수 있도록 합니다.
- 삽입 또는 클래스에 특정 멤버 변수에서 추출 합니다.삽입 및 추출 연산자는 데이터 읽기 및 쓰기에 보관 클래스와 상호 작용 합니다.
다음 예제에서는 구현 하는 방법을 보여 줍니다. Serialize에 CPerson 클래스 선언 위에서:CPP File의 Serialize멤버 함수 재정의123456789101112void
CPerson::Serialize( CArchive& archive )
{
// call base class function first
// base class is CObject in this case
CObject::Serialize( archive );
// now do the stuff for our specific class
if
( archive.IsStoring() )
archive << m_name << m_number;
else
archive >> m_name >> m_number;
}
DECLARE_SERIAL 매크로 serialization을 지 원하는 클래스의 선언에 필요한 다음과 같은:
head Fileclass CPerson : public CObject { public: DECLARE_SERIAL( CPerson )
Cpp 파일에 IMPLEMENT_SERIAL 매크로 지정처음 두 개의 인수에 매크로 해당 직접 기본 클래스의 이름과 클래스의 이름입니다.
이 매크로 세 번째 인수는 스키마 번호입니다. 스키마 개체 클래스에 대 한 버전 번호입니다.
스키마 번호는 0 보다 크거나 같은 정수를 사용 합니다. (이 스키마 번호 데이터베이스 용어와 혼동 하지 마십시오.)MFC serialization 코드는 메모리에 개체를 읽을 때 스키마 번호를 확인 합니다.
스키마 번호 디스크 개체의 메모리에 있는 클래스 스키마 수가 일치 하지 않으면, 라이브러리 throw 합니다
CArchiveException, 프로그램이 잘못 된 버전의 개체를 읽는 것을 방지 합니다.원하는 경우에 Serialize 멤버 함수의 여러 버전을 읽을 수 있도록 — 응용 프로그램의 다른 버전으로 작성 된 파일-값을 사용할 수 있습니다VERSIONABLE_SCHEMA 인수로IMPLEMENT_SERIAL 매크로. 사용 정보 및 예제에 대 한 참조를 GetObjectSchema 클래스의 멤버 함수 CArchive.
다음 예제에서는 사용 하는 방법을 보여 줍니다. IMPLEMENT_SERIAL 클래스인 CPerson, 즉 파생 CObject:
Cpp 파일 상단IMPLEMENT_SERIAL( CPerson, CObject, 1 )
Serializable 클래스를 이용한 가변배열 저장하고 불러오기
일반적으로 정형화되어 있는 Docuemt의 경우 또는 크기자 적은 파일의 경우 Serializable 클래스를 사용하지 않고서 작업하는 경우가 있다.
예를 들어 DB를 사용하는 경우라면 Serialize를 사용하지 않는 경우도 있다.그러나 동적 배열을 사용하는 경우는 Serialize를 구현하지 않으면 거의 작업이 불가능하다.
CListCtrl,CTreeCtrl의 경우를 생각해보자, 이들은 저장해야 하는 Item이 가변적이므로 Item의 수 모두를 저장하고 불러올 수 있어야 한다.
다행하게도 이들 클래스는 Serializable이 구현되어 있으므로 그대로 사용하면 된다.다음의 예를 살펴보자 Serialization을 수행할 때 문제가 될 부분이 있다
head 파일 예)class SaveFile :public CObject { DECLARE_SERIAL(SaveFile) public: SaveFile(void); public: SaveFile(SaveFile &Sv) { *this=Sv; } public: ~SaveFile(void); public : CString FName; public: char *FData; public : ULONGLONG MySize; public: virtual void Serialize(CArchive &pArchive); public: SaveFile& operator=(SaveFile & SvFi); };
CPP 파일(잘못된 경우)
123456789101112void
SaveFile::Serialize(CArchive & pArchive)
{
CObject::Serialize(pArchive);
if
(pArchive.IsStoring())
{
pArchive<<FName<<MySize<<FData;
}
else
{
pArchive>>FName>>MySize>>FData;
}
}
위의 경우에서 FData의 처리부분에서 문제가 발생한다.
자세히 살펴보면 FData는 문자열 Point로 선언되어 있으므로 메모리의 주소만 저장하고 실제 Data는 저장되지 않는다.
이와 유사하게 직접 만든 클래스,혹은 Struct의 경우 CArray<SaveFile*, SaveFile*> SF; 와 같은 형태로 동적으로 조작할 목적으로 설계 되었다면
심각한 문제를 일으킨다. 어플리케이션이 종료되면 메모리가 해제 되기 때문에 파일을 읽어서 메모리 주소는 아무 쓸모가 없어진다.
정상적으로 동작하려면 아래와 같이 코딩 되어야 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | void SaveFile::Serialize(CArchive & pArchive) { CObject::Serialize(pArchive); if (pArchive.IsStoring()) { pArchive<<FName<<MySize; for ( int i= 0 ;i<MySize;i++) { pArchive<<FData[i]; } } else { pArchive>>FName>>MySize; FData= new char [MySize]; for ( int i= 0 ;i<MySize;i++) { pArchive>>FData[i]; } } } |
즉 Point를 사용하였으므로 메모리 크기를 할당하고 메모리에 내용을 기록 해주어야 한다는 것이다.
CArray_Serialize_Source_Files.zip
'개발언어 > c++' 카테고리의 다른 글
ON_UPDATE_COMMAND_UI_RANGE(사용자 UI갱신매크로) (0) | 2017.08.09 |
---|---|
MFC 다수의 컨트롤 메지시를 한꺼번에 처리하기(Handlers for Message-Map Ranges) (0) | 2017.08.07 |
fatal error C1001 (0) | 2017.01.02 |
afxv_w32.h(16) : fatal error C1189: #error : WINDOWS.H already included. MFC apps must not #include (0) | 2017.01.02 |
상속된 템플릿 클래스의 연산자 오버로딩(Operator Overloading) (0) | 2016.11.21 |