1.65k likes | 2.01k Views
Chap. 4. Utility Classes. Contents. Simple value types 일반적 목적 : CString, CTime, CTimeSpan 윈도우 구조체 : CPoint, CSize, Crect MFC collection classes array, linked list, map CFile class family CException class. Introduction. 우리가 만드는 많은 class 들 Utility class 의 범주에 든다. 이 단원의 목적
E N D
Chap. 4 Utility Classes
Contents • Simple value types • 일반적 목적 : CString, CTime, CTimeSpan • 윈도우 구조체 : CPoint, CSize, Crect • MFC collection classes • array, linked list, map • CFile class family • CException class
Introduction • 우리가 만드는 많은 class들 • Utility class의 범주에 든다. • 이 단원의 목적 • MFC 개발자 들의 technique • 앞으로의 project에 도움
Simple Value Types • Simple value types • C++ type(char*, …), Windows type(RECT, …) 들을 encapsulating 한 클래스들 • C++ interface 제공 • 더 안전하고 더 쉽게 이용할 수 있는 operator 제공 • memory management • internationalization • …
Class CString • Character string을 encapsulate함 • 다음과 같은 특징이 있음 • Internationalization • Memory allocation/deallocation • Operators(+, =, ==, …) • String searching • String manipulation(reverse, concat) • Formatting(printf-like)
Using a CString • 생성 // create a CString from a char * CString myString1(“This is a string”); // create a CString from a CString CString myString2(myString1); // create a CString with 80 z characters CString myString3(‘z’, 80); // create a CString as empty CString CString myString4;
Using a CString (cont’d) CString myString1(“string 1”); CString myString2(“string 2”); CString myString3(“string 3”); // addition (concatenation) & assignment myString1 += myStrig2; myString3 = “This is “ + myString2; myString2 += ‘Z’; // comparison : == , < , != , … if ( myString1 == myString2 ) // like strcmp // operator[] : 0-based if ( myString1[7] == ‘l’ ) // find : Find(), FindOneOf(), ReverseFind()
CString Internals • CString declaration(AFX.H) class CString { public: // Constructors CString(); CString(const CString& stringSrc); CString(TCHAR ch, int nRepeat = 1); CString(LPCSTR lpsz); CString(LPCWSTR lpsz); CString(LPCSTR lpch, int nLength); CString(LPCWSTR lpch, int nLength); CString(const unsigned char* psz);
CString Internals (cont’d) // Attributes & Operations int GetLength() const; BOOL IsEmpty() const; void Empty(); TCHAR GetAt(int nIndex) const; TCHAR operator[](int nIndex) const; void SetAt(int nIndex, TCHAR ch); operator LPCTSTR() const; const CString& operator=(const CString& stringSrc); const CString& operator=(TCHAR ch); const CString& operator=(LPCSTR lpsz); const CString& operator=(LPCWSTR lpsz); const CString& operator=(const unsigned char* psz);
CString Internals (cont’d) // concatenate const CString& operator+=(const CString& string); const CString& operator+=(TCHAR ch); const CString& operator+=(LPCTSTR lpsz); friend CString AFXAPI operator+(const CString& string1, const CString& string2); friend CString AFXAPI operator+(const CString& string, TCHAR ch); friend CString AFXAPI operator+(TCHAR ch, const CString& string); friend CString AFXAPI operator+(const CString& string, LPCTSTR lpsz); friend CString AFXAPI operator+(LPCTSTR lpsz, const CString& string); // string comparison int Compare(LPCTSTR lpsz) const; int CompareNoCase(LPCTSTR lpsz) const; int Collate(LPCTSTR lpsz) const; int CollateNoCase(LPCTSTR lpsz) const;
CString Internals (cont’d) // simple sub-string extraction CString Mid(int nFirst, int nCount) const; CString Mid(int nFirst) const; CString Left(int nCount) const; CString Right(int nCount) const; CString SpanIncluding(LPCTSTR lpszCharSet) const; CString SpanExcluding(LPCTSTR lpszCharSet) const; // upper/lower/reverse conversion void MakeUpper(); void MakeLower(); void MakeReverse(); // advanced manipulation int Replace(TCHAR chOld, TCHAR chNew); int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew); int Remove(TCHAR chRemove); int Insert(int nIndex, TCHAR ch); int Insert(int nIndex, LPCTSTR pstr); int Delete(int nIndex, int nCount = 1);
CString Internals (cont’d) // searching int Find(TCHAR ch) const; int ReverseFind(TCHAR ch) const; int Find(TCHAR ch, int nStart) const; int FindOneOf(LPCTSTR lpszCharSet) const; int Find(LPCTSTR lpszSub) const; int Find(LPCTSTR lpszSub, int nStart) const; // simple formatting void AFX_CDECL Format(LPCTSTR lpszFormat, ...); void AFX_CDECL Format(UINT nFormatID, ...); void FormatV(LPCTSTR lpszFormat, va_list argList); // input and output friend CArchive& AFXAPI operator<<(CArchive& ar, const CString& string); friend CArchive& AFXAPI operator>>(CArchive& ar, CString& string); // load from string resource BOOL LoadString(UINT nID);
CString Internals (cont’d) // get pointer to modifiable buffer at least as long as nMinBufLength LPTSTR GetBuffer(int nMinBufLength); // release buffer, setting length to nNewLength (or to first nul if -1) void ReleaseBuffer(int nNewLength = -1); // get pointer to modifiable buffer exactly as long as nNewLength LPTSTR GetBufferSetLength(int nNewLength); // release memory allocated to but unused by string void FreeExtra(); // turn refcounting back on LPTSTR LockBuffer(); // turn refcounting off void UnlockBuffer(); // Implementation public: ~CString(); int GetAllocLength() const;
CString Internals (cont’d) protected: LPTSTR m_pchData; // pointer to ref counted string data // implementation helpers CStringData* GetData() const; void Init(); void AllocCopy(CString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const; void AllocBuffer(int nLen); void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData); void ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data, int nSrc2Len, LPCTSTR lpszSrc2Data); void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData); void CopyBeforeWrite(); void AllocBeforeWrite(int nLen); static void PASCAL Release(CStringData* pData); static int PASCAL SafeStrlen(LPCTSTR lpsz); static void FASTCALL FreeData(CStringData* pData); };
CString Internals (cont’d) • CString declaration(AFX.H) • m_pchData • 유일한 멤버 변수 • String에 대한 pointer • CStringData • CString의 기능 구현을 도와주는 structure struct CStringData { long nRefs; // reference count int nDataLength; // length of data (including terminator) int nAllocLength; // length of allocation TCHAR* data() // TCHAR* to managed data { return (TCHAR*)(this+1); } };
CString Internals (cont’d) • 공간 할당 함수 AllocBuffer()(STRCORE.CPP) void CString::AllocBuffer(int nLen) { if (nLen == 0) Init(); else { CStringData* pData = (CStringData*)newBYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)]; pData->nAllocLength = nLen; pData->nRefs = 1; pData->data()[nLen] = '\0'; pData->nDataLength = nLen; m_pchData = pData->data(); } }
CStringData Data(nlength + 1) nRefs nDataLength nAllocLength CString::m_pchData CString Internals (cont’d) • AllocBuffer()함수에 의한 memory 할당
CString Internals (cont’d) • 의문점 • CString class는 string 이외의 데이터를 숨김 • 왜, 그들을 멤버변수로 추가하지 않았는가 • CString object와 TCHAR *은 똑같아야 한다. • same bits • 그 이외의 부가적인 정보는 CStringData 에서 관리 • 이전 버전과의 호환성
CString Internals (cont’d) • Reference counting • CStringData::nRefs • 실제 데이터의 변경이 가해지면 copy CString myString1(“This is a string”); CString myString2(myString1); CString myString3 = myString1; myString2 myString1 “This is a string” myString3
CString Internals (cont’d) • Reference counting 과정 • nRefs 변수의 값이 -1 으로 초기화 • 그 string에 새 참조가 발생하면 1 증가 • 참조가 줄어들면 1 감소 • 다시 0이 되면 삭제 가능 • 참조되는 string에 쓰기가 발생하면 새로운 string을 생성하고 원래의 string의 nRefs값을 1 감소 • Critical resource • 일종의 OS에서 발생하는 resource 공유 문제 • 두 thread 에서 동시에 참조를 증가 혹은 감소시키는 경우 문제 해결 • InterlockedIncrement(), InterlockedDecrement()
CString Internals (cont’d) • 예제 Line 1 Line 2 Line 3 Line 4 Line 5 CString myString1(“This is mystring1”); CString myString2(myString1); CString myString3; myString3 = myString2; // Write somthing myString3.MakeUpper();
CString Internals (cont’d) “Strcore.cpp” CString::CString(LPCTSTR lpsz) { int nLen = SafeStrlen(lpsz); if (nLen != 0) { AllocBuffer(nLen); memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR)); } } myString1 “This is my string1” 1
CString Internals (cont’d) CString::CString(const CString& stringSrc) { if (stringSrc.GetData()->nRefs >= 0) { m_pchData = stringSrc.m_pchData; InterlockedIncrement(&GetData()->nRefs); } else { Init(); *this = stringSrc.m_pchData; } } myString1 “This is my string1” 2 myString2
CString Internals (cont’d) const CString& CString::operator=(const CString& stringSrc) { if (m_pchData != stringSrc.m_pchData) { if ((GetData()->nRefs < 0 && GetData() != _afxDataNil) || stringSrc.GetData()->nRefs < 0) { // actual copy necessary since one of the strings is locked AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData); } else { // can just copy references around Release(); m_pchData = stringSrc.m_pchData; InterlockedIncrement(&GetData()->nRefs); } } return *this; } myString2 myString1 “This is my string1” 3 myString3
CString Internals (cont’d) void CString::MakeUpper() { CopyBeforeWrite(); _tcsupr(m_pchData); } void CString::CopyBeforeWrite() { if (GetData()->nRefs > 1) { CStringData* pData = GetData(); Release(); AllocBuffer(pData->nDataLength); memcpy(m_pchData,pData->data(), (pData->nDataLength+1)*sizeof (TCHAR)); } ASSERT(GetData()->nRefs <= 1); }
CString Internals (cont’d) void CString::Release() { if (GetData() != _afxDataNil) { ASSERT(GetData()->nRefs != 0); if (InterlockedDecrement(&GetData()->nRefs) <= 0) FreeData(GetData()); Init(); } } myString1 “This is my string1” 2 myString2 myString3 “THIS IS MY STRING1” 1
CString Internals (cont’d) • Internationalization • _t internationalized string 함수를 이용하여 구현 • _tcschr() => strchr() mapping int CString::Find(TCHAR ch, int nStart) const { int nLength = GetData()->nDataLength; if (nStart >= nLength) return -1; LPTSTR lpsz = _tcschr(m_pchData + nStart, (_TUCHAR)ch); return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData); }
Class CRect • Declaration (AFXWIN.H) class CRect : public tagRECT { … typedef struct tagRECT { LONG left; LONG top; LONG right; LONG bottom; } RECT;
Class CRect (cont’d) void CRect::DeflateRect(LPCRECT lpRect) { left += lpRect->left; top += lpRect->top; right -= lpRect->right; bottom -= lpRect->bottom; }
MFC Collection Classes • MFC collection classes • Array • 일반적인 C++에서의 array임 • 단 모든 메모리관련 기능 추가 • List • Doubly linked list • Map • 일종의 dictionary • Key, value 쌍으로 데이터를 저장
Type of Collection Classes • Template-based • Nontemplate-based • Array : CObArray, CByteArray, … • List : CObList, CPtrList, CStringList • Map : CMapPtrToWord, …
Type-safe Collection • Template-based classes • 변수 선언 • 멤버 함수 호출 • 필요할 경우, helper function 구현 (CArray, CList, CMap 에서) • CompareElements • CopyElements • Dumpelements • HashKey • SerializeElements
Type-safe Collection (cont’d) // 변수 선언 CList<int, int> m_intList; // 함수 호출 m_intList.AddTail( 100 ); m_intList.RemoveAll( ); // helper function 구현 class CPerson : public CObject { . . . }; CArray< CPerson, CPerson& > personArray; template <> void AFXAPI SerializeElements <CPerson> ( CArchive& ar, CPerson* pNewPersons, int nCount ) { for ( int i = 0; i < nCount; i++, pNewPersons++ ) { // Serialize each CPerson object pNewPersons->Serialize( ar ); } }
Type-safe Collection (cont’d) • Nontemplate-based classes • 방법 1 : Type-casting 활용 • 방법 2 : 파생클래스 생성 class CPerson : public CObject {...}; CPerson* p1 = new CPerson(...); CObList myList; myList.AddHead( p1 ); // No cast needed CPerson* p2 = ( CPerson* )myList.GetHead(); class CPersonList : public CObList { public: void AddHeadPerson( CPerson* person ) {AddHead( person );} const CPerson* GetHeadPerson() {return (CPerson*)GetHead();} };
Iteration • Array • List CTypedPtrArray<CObArray, CPerson*> myArray; for( int i = 0; i < myArray.GetSize();i++ ){ CPerson* thePerson = myArray.GetAt( i ); // CPerson* thePerson = myArray[ i ]; } CTypedPtrList<CObList, CPerson*> myList; POSITION pos = myList.GetHeadPosition(); while( pos != NULL ) { CPerson* thePerson = myList.GetNext( pos ); ... }
Iteration (cont’d) • Map CMap<CString, LPCTSTR, CPerson*, CPerson*> myMap; POSITION pos = myMap.GetStartPosition(); while( pos != NULL ) { CPerson* pPerson; CString string; myMap.GetNextAssoc( pos, string, pPerson ); } CMapStringToOb myMap; // A nontemplate collection class POSITION pos = myMap.GetStartPosition( ); while( pos != NULL ) { CPerson* pPerson; CString string; myMap.GetNextAssoc( pos, string, (CObject*&)pPerson ); ASSERT( pPerson->IsKindOf( RUNTIME_CLASS( CPerson ) ) ); }
Additional Structures • Stack class CTray : public CObject { ... }; class CStack : public CTypedPtrList< CObList, CTray* > { public: // Add element to top of stack void Push( CTray* newTray ) { AddHead( newTray ); } // Peek at top element of stack CTray* Peek() { return IsEmpty() ? NULL : GetHead(); } // Pop top element off stack CTray* Pop() { return RemoveHead(); } };
Additional Structures (cont’d) • Queue class CPerson : public CObject { ... }; class CQueue : public CTypedPtrList< CObList, CPerson* > { public: // Go to the end of the line void AddToEnd( CPerson* newPerson ) { AddTail( newPerson ); } // End of the queue // Get first element in line CPerson* GetFromFront() { return IsEmpty() ? NULL : RemoveHead(); } };
Array Collections • Array collections • CByteArray, CDWordArray, CUintArray • CObArray, CStringArray, CWordArray • AFXCOLL.H • ARRAY_X.CPP ( X : type of array ) void ArrayExample() { CUintArray myIntArray; myIntArray.SetSize(100); for ( int I=0; I<100; I++ ) myIntArray.SetAt(I, 2*I); UINT bogus = myIntArray[50]; bogus = myIntArray.GetAt(50); myIntArray.DeleteAt(50); }
CWordArray Class class CWordArray : public CObject { DECLARE_SERIAL(CWordArray) public: // Attributes int GetSize() const; int GetUpperBound() const; void SetSize(int nNewSize, int nGrowBy = -1); // Operations void FreeExtra(); void RemoveAll(); WORD GetAt(int nIndex) const; void SetAt(int nIndex, WORD newElement); WORD& ElementAt(int nIndex);
CWordArray Class (cont’d) // Direct Access to the element data (may return NULL) const WORD* GetData() const; WORD* GetData(); // Potentially growing the array void SetAtGrow(int nIndex, WORD newElement); int Add(WORD newElement); int Append(const CWordArray& src); void Copy(const CWordArray& src); // overloaded operator helpers WORD operator[](int nIndex) const; WORD& operator[](int nIndex); // Operations that move elements around void InsertAt(int nIndex, WORD newElement, int nCount = 1); void RemoveAt(int nIndex, int nCount = 1); void InsertAt(int nStartIndex, CWordArray* pNewArray);
CWordArray Class (cont’d) // Implementation protected: WORD* m_pData; // the actual array of data int m_nSize; // # of elements (upperBound - 1) int m_nMaxSize; // max allocated int m_nGrowBy; // grow amount public: ~CWordArray(); void Serialize(CArchive&); #ifdef _DEBUG void Dump(CDumpContext&) const; void AssertValid() const; #endif protected: // local typedefs for class templates typedef WORD BASE_TYPE; typedef WORD BASE_ARG_TYPE; };
CWordArray Class (cont’d) • CWordArray(ARRAY_W.CPP) • 멤버 변수 • m_pData • 저장된 데이터의 포인터 • m_nSize • Current size of array(“logical” size) • m_nMaxSize • “Physical” size • M_nGrowBy • 추가 메모리 할당시 추가 할당 크기 • SetSize()를 통한 이해
CWordArray Class (cont’d) void CWordArray::SetSize(int nNewSize, int nGrowBy) { if (nGrowBy != -1) m_nGrowBy = nGrowBy; // set new size if (nNewSize == 0) { // shrink to nothing delete[] (BYTE*)m_pData; m_pData = NULL; m_nSize = m_nMaxSize = 0; } else if (m_pData == NULL) { // create one with exact size m_pData = (WORD*) new BYTE[nNewSize * sizeof(WORD)]; memset(m_pData, 0, nNewSize * sizeof(WORD)); // zero fill m_nSize = m_nMaxSize = nNewSize; }
CWordArray Class (cont’d) else if (nNewSize <= m_nMaxSize) { // it fits if (nNewSize > m_nSize) { // initialize the new elements memset(&m_pData[m_nSize], 0, (nNewSize-m_nSize) * sizeof(WORD)); } m_nSize = nNewSize; } else { // otherwise, grow array int nGrowBy = m_nGrowBy; if (nGrowBy == 0) nGrowBy = min(1024, max(4, m_nSize / 8)); int nNewMax; if (nNewSize < m_nMaxSize + nGrowBy) nNewMax = m_nMaxSize + nGrowBy; // granularity else nNewMax = nNewSize; // no slush WORD* pNewData = (WORD*) new BYTE[nNewMax * sizeof(WORD)];
CWordArray Class (cont’d) // copy new data from old memcpy(pNewData, m_pData, m_nSize * sizeof(WORD)); memset(&pNewData[m_nSize], 0, (nNewSize-m_nSize)*sizeof(WORD)); // get rid of old stuff (note: no destructors called) delete[] (BYTE*)m_pData; m_pData = pNewData; m_nSize = nNewSize; m_nMaxSize = nNewMax; } }
CWordArray Class (cont’d) • SetSize()(ARRAY_W.CPP) • 5개의 section으로 구성 • Initialization section • Shrink-to-nothing section • First allocation section • Allocate-from-extra-space section • Grow-the-array section
CWordArray Class (cont’d) • SetAt()(AFXCOLL.INL) • m_pData[nIndex] = newElement; • InsertAt()(ARRAY_W.CPP) • Array마지막에 insert하는 경우 • 메모리 할당 후 insert • Array 중간에 insert하는 경우 • 메모리 할당 후 데이터 이동작업 • Expensive 무분별한 사용을 삼가