Overview 유틸리티클래스와집합클래스 유틸리티클래스를이용하여객체생성법과사용법 MFC 에서 C++ 의업캐스팅이적용되는원리이해 배열, 리스트, 맵클래스동작원리와사용법 HCI Programming 2 (321190) 2007년가을학기 9/20/2007 박경신 2 콘솔응용프로그램 특징 메시지구동방식을사용하지않으므로 C/C++ 언어에대한지식만있으면곧바로실습이가능하다. 상당수의 MFC 클래스를사용할수있다. 유틸리티클래스, 집합클래스, 파일입출력클래스,... 알고리즘을개발할때유용하다. MFC 콘솔응용프로그램작성 프로젝트생성 3 4
MFC 콘솔응용프로그램작성 1 단계옵션설정 MFC 콘솔응용프로그램분석 파일구성 stdafx.h, stdafx.cpp 미리컴파일된헤더 Console.rc, Resource.h 리소스정보 Console.h, Console.cpp 구현코드 5 6 MFC 콘솔응용프로그램분석 stdax.f.h 미리컴파일된헤더생성 MFC 에서사용하는헤더화일은크기가커서컴파일시간이오래걸림 사용할헤더파일을 stdafx.h 에선언하면컴파일러가헤더를미리컴파일하여 *.pch 파일로저장함. 다음컴파일때시간이단축할수있음. Console.rc 프로그램에서사용할리소스는 *.rc 파일로작성됨 Resource view 에서볼수있음 Resource.h 프로그램에서해당리소스를 MACRO 상수값으로참조가능 7 MFC 콘솔응용프로그램분석 Console.cpp 코드 CString 객체생성하고, CString 멤버함수인 LoadString() 을이용하여리소스에서문자열을 load 한후 cout 을이용하여화면에출력 CWinApp theapp; // 유일한전역응용프로그램객체 // CWinApp 클래스를그대로이용 using namespace std; // 표준 C++ 라이브러리를사용 int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) int nretcode = 0; if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine( ), 0)) cerr << _T("Fatal Error: MFC initialization failed") << endl; nretcode = 1; 8 MFC를사용하기위한초기화함수
MFC 콘솔응용프로그램분석 Console.cpp MFC 콘솔응용프로그램분석 문자열리소스 CString strhello; // CString 객체를생성 strhello.loadstring(ids_hello); // 리소스에서문자열을 load cout << (LPCTSTR)strHello << endl; // 화면출력 return nretcode; 이부분을바꿔본다 9 10 MFC 콘솔응용프로그램분석 실행 (CTRL+F5) MFC 콘솔응용프로그램분석 실행파일생성과정 console.h, stdafx.h console.cpp, stdafx.cpp 컴파일러 console.obj stdafx.obj API & MFC 라이브러리 C/C++ 라이브러리 resource.h 링커 console.exe console.rc 각종리소스 ( 문자열, 아이콘,...) 리소스컴파일러 console.res 11 12
Data Type & Data Type Class 변수명명법 API 데이터타입 데이터타입클래스 CString CPoint, CRect, CZize CTime, CTimeSpan 집합클래스 CArray CList CMap 변수명명법 윈도우프로그램에서는변수명을헝가리언표기법을사용 변수이름앞에데이터형식을의미하는접두어를사용하여명명 변수의형식에대한불일치오류방지 프로그램해독, 유지, 보수에용이 13 14 접두어 a by 데이터타입 Array BYTE (unsigned char) 사용예 char achname[10] BYTE bych API Data Type b ch cb dw fn h BOOL(int) Char Count of Bytes DWORD(unsigned long) Function Handle BOOL bfind char chvalue BYTE cbloop DWORD dwsum void fngetdata() HDC hdc, HWND hwnd API 데이터타입 기본형 (windef.h) 데이터타입 BOOL or BOOLEAN BYTE, WORD, DWORD, LONG 정의 TRUE or FALSE 8 비트, 16 비트, 32 비트, 32 비트 ( 모두 unsigned) i l lp n np pt r s sz m w Index LONG Long (or far) pointer Short or int Near(or short) pointer POINT(x, y pointer) RECT(Rectangelstructure) String Null-teminated string data member in Class WORD(unsigned int) int iname LONG lparam LPSTR lpbuffer int n char * npstr POINT ptstr RECT rscreen char sadderss[40] char szmsg[] LONG m_id 15 WORD wnum U* HANDLE H* unsigned * 예 ) UCHAR, UINT, ULONG,... 32 비트핸들 * 을가리키는핸들예 ) HBITMAP( 비트맵 ), HBRUSH( 브러시 ), HCURSOR( 커서 ), HDC( 디바이스컨텍스트 ), HFONT( 폰트 ), HICON( 아이콘 ), HINSTANCE( 인스턴스 ), HMENU( 메뉴 ), HPEN( 펜 ), HWND( 윈도우 ) 16
API Data Type API 데이터타입 기본형 (windef.h) 데이터타입 P* = LP* (L)PSTR, (L)PCSTR (L)PTSTR, (L)PCTSTR COLORREF 정의 * 에대한포인터예 1) PBOOL, PBYTE, PLONG,... 예 2) LPBOOL, LPBYTE, LPLONG,... ANSI 문자열 ANSI 또는유니코드문자열 32 비트 RGB (red, green, blue 각각 8 비트 ) 색상값 17 Unicode ASCII code 8-bit로표현할수있는256자 영어나라틴어권에서는상관없음 한국, 일본, 중국, 아랍등의다양한문자들을표현하는데는한계 Unicode 세계각국의언어를통일된방법으로표현할수있게제안된국제적인코드규약 비트문자코드인 ASCII 코드를 16-bit로확장 전세계의모든문자를표현하는표준코드 11,172자의한글을연속된공간에가나다라순서로 가 에서 ㅎ 까지코드화하는방식이유니코드기술위원회 (UTC) 에서채택한유니코드 2.0 규격임. Windows NT, C언어, Java s native encoding이유니코드지원 장점- 하나의캐릭터로표현 단점 - 메모리공간을두배차지 18 API Data Type 유틸리티클래스 API 데이터타입 - 구조체 데이터타입정의용도 POINT typedef struct tagpoint LONG x; LONG y; POINT, *PPOINT; RECT typedef struct tagrect LONG left; LONG top; LONG right; LONG bottom; RECT, *PRECT; SIZE typedef struct tagsize LONG cx; LONG cy; SIZE, *PSIZE; 점의 x, y 좌표 ( 주로마우스커서의위치를나타낼때사용한다.) 사각형왼쪽상단과오른쪽하단좌표 사각형폭과높이 19 데이터타입 Class CString CPoint CRect CSize CTime CTimeSpan 20
CString 클래스 기능 문자열처리 대부분의 MFC 지원함수처럼 dll로제공 코드의크기가줄어듬 다양한초기화방법, 멤버함수, 연산자등을지원 손쉽게문자를처리 CString 클래스 특성 가변길이문자열을지원 프로그램실행도중문자열길이를자유롭게바꿀수있다. 최대길이는 (INT_MAX - 1) 이다. const char* 나 LPCTSTR 대신 CString 객체를직접사용가능 이때는 CString 객체에대해 (LPCTSTR) 연산자를명시적으로적용하는것이좋다. CString str = " 안녕하세요."; cout << (LPCTSTR)str << endl; // 실행결과? cout << str << endl; // 실행결과? (LPCTSTR) 을제거하면 Unicode 로 casting 이되지않음 21 22 CString 클래스 객체생성및초기화 Console.cpp 에서다음을추가해본다. CString str1; str1 = " 안녕하세요."; CString str2(" 오늘은 "); CString str3(str2); CString str4 = str1 + " " + str2 + " 즐거운날입니다."; cout << (LPCTSTR)str1 << endl; cout << (LPCTSTR)str2 << endl; cout << (LPCTSTR)str3 << endl; cout << (LPCTSTR)str4 << endl; str4 += " 하하하 "; cout << (LPCTSTR)str4 << endl; CString 클래스 CString::Format( ) sprintf 와같이데이터를문자열로변환하여출력 CString str; str.format("x=%d, y=%d", 100, 200); MessageBox(NULL, (LPCTSTR)str, "CString 연습 ", MB_OK); CString::LoadString( ) 문자열테이블로부터문자열리소스를로드 CString str; str.loadstring(ids_hello); MessageBox(NULL, (LPCTSTR)str, "CString 연습 ", MB_OK); 23 24
CString 클래스 문자열변환 int CString::Replace(const char* s1, const char* s2) 객체의문자열중모든 s1을 s2로변경후변경된횟수반환 문자열검색 int CString::Find(const char* s) 객체의문자열에서 s를찾아인덱스위치를리턴 문자열삭제 int CString::Delete(int index, int count) index 위치에서 count 개의문자를제거후제거된문자수반환 문자열삽입 int CString::Insert(int index, const char* s) index 위치에 s를삽입 문자열길이 int GetLength( ) 문자열초기화 void Empty( ); 문자열추출 CString Mid( int nfirst ) CString Mid( int nfirst, int ncount ) 25 CString Left( int ncount ) CString Right( int ncount ) CPoint, CRect, CSize 클래스 클래스정의 클래스이름 CPoint CRect CSize 업캐스팅 정의 class CPoint : public POINT class CRect : public RECT class CSize : public SIZE 하위클래스가상위클래스로형변환 void SomeFunc(RECT* rect)... RECT r1; CRect r2; SomeFunc(&r1); // OK! SomeFunc(&r2); // OK! (Upcasting) 26 CPoint 클래스 생성자 CRect 클래스 생성자 CPoint::CPoint (int x, int y); 예제 CPoint pt1(10, 20); POINT pt = 30, 40; CPoint pt2(pt); pt1.offset(40, 30); // 40, 30을더함 pt2.offset(20, 10); // 20, 10을더함 if(pt1 == pt2) cout << " 두점의좌표가같습니다." << endl; cout << " 두점의좌표가다릅니다." << endl; 27 CRect::CRect (int l, int t, int r, int b); CRect::CRect (const RECT& srcrect); CRect::CRect (LPCRECT lpsrcrect); CRect::CRect (POINT point, SIZE size); CRect::CRect (POINT topleft, POINT bottomright); 사각형의폭과높이 int CRect::Width (); int CRect::Height (); 좌표가사각형의내부인지외부인지포함여부판단 BOOL CRect::PtInRect (POINT point); 28
CRect 클래스 CSize 클래스 예제 생성자 CRect rect1; rect1.setrect(0, 0, 200, 100); CRect rect2(0, 0, 200, 100); if(rect1 == rect2) cout << " 두사각형의좌표가같습니다." << endl; cout << " 두사각형의좌표가다릅니다." << endl; CSize::CSize (int x, int y); CSize::CSize (SIZE initsize); CSize::CSize (POINT initpoint); CSize::CSize (DWORD dwsize); 예제 RECT rect = 100, 100, 300, 200; CRect rect3(rect); cout << rect3.width() << " " << rect3.height() << endl; CPoint pt(200, 150); if(rect3.ptinrect(pt)) cout << " 점이사각형내부에있습니다." << endl; cout << " 점이사각형외부에있습니다." << endl; 29 CSize size1(100, 200); // 폭과높이지정 SIZE size = 100, 200; CSize size2(size); cout << size2.cx << " " << size2.cy << endl; if(size1 == size2) // 두객체내용이같은지확인한다. cout << " 크기가같습니다." << endl; cout << " 크기가다릅니다." << endl; 30 CTime, CTimeSpan 클래스 CTime 클래스 CTime 클래스 (afx.h) 절대적인시간 ( 예를들면, 현재시각 ) 을처리 CTimeSpan 클래스 (afx.h) 시간의차이값을처리 두클래스모두내부적으로시간값을 64 비트로저장 생성자 CTime::CTime (const CTime& timesrc ); CTime::CTime (time_t time ); CTime::CTime (int nyear, int nmonth, int nday, int nhour, int nmin, int nsec, int ndst = -1 ); CTime::CTime (WORD wdosdate, WORD wdostime, int ndst = -1 ); 예제 // 현재시각구하기 CTime thetime; thetime = CTime::GetCurrentTime(); 요일, 월날짜, 연도 // 화면에출력하기 CString str = thetime.format("%a, %B %d, %Y"); cout << (LPCTSTR)str << endl; str.format(" 현재시각은 %d시 %d분입니다.", thetime.gethour(), thetime.getminute()); cout << (LPCTSTR)str << endl; 31 32
CTimeSpan 클래스 예제 // 시간차구하기 CTime starttime = CTime::GetCurrentTime(); Sleep(2000); // 2 sec CTime endtime = CTime::GetCurrentTime(); CTimeSpan elapsedtime = endtime - starttime; CString str; str.format("%d초가지났습니다.", elapsedtime.gettotalseconds()); cout << (LPCTSTR)str << endl; 집합클래스 집합클래스 (Collection Class) Array, linked list, map 과같은자료구조를좀더편리하게사용할수있도록 MFC 에서제공하는클래스 Array List Map 33 34 배열 배열 (Array) 의단점 원소를삽입하거나삭제시인접원소를이동해야하므로속도저하 배열인덱스를잘못참조해도오류를발생시키지않음 배열의크기가고정적 MFC는이런문제해결을위하여멤버함수를추가한다양한종류의배열클래스를제공 Template 클래스 Nontemplate 클래스 배열클래스 MFC 배열클래스의특징 배열인덱스를잘못참조하는경우오류를발생시킨다. 배열크기가가변적이다. 템플릿클래스 afxtempl.h 헤더파일 원하는종류의데이터타입을프로그래머가결정 클래스이름 데이터타입 사용예 CArray 프로그래머가결정 CArray<CPoint, CPoint&> array; 35 36
배열클래스 배열클래스 비템플릿클래스 afxcoll.h 헤더파일 각클래스마다데이터타입이있다 클래스이름 데이터타입 CByteArray BYTE CWordArray WORD CDWordArray DWORD CUIntArray UINT CStringArray CString CPtrArray void 포인터 사용예 CByteArray array; CWordArray array; CDWordArray array; CUIntArray array; CStringArray array; CPtrArray array; 생성과초기화 배열객체를생성 SetSize 를호출하여크기를설정 초기화 / 접근시 [] 연산자를이용 CStringArray array; array.setsize(5); for(int i=0; i<5; i++) CString string; string.format("%d 년이지났습니다.", i*10); array[i] = string; for(i=0; i<5; i++) cout << (LPCTSTR)array[i] << endl; CObArray CObject 포인터 CObArray array; 37 38 배열클래스 배열클래스 원소삽입과삭제 CUIntArray array; array.setsize(5); for(int i=0; i<5; i++) array[i] = i; // 배열원소삽입 InsertAt(index, 값 ) array.insertat(3, 77);\ for(i=0; i<array.getsize(); i++) // 배열의현재크기 GetSize() cout << array[i] << endl; cout << endl; // 배열원소삭제 Remove(index) array.removeat(3); for(i=0; i<array.getsize(); i++) cout << array[i] << endl; 39 템플릿배열클래스 사용자가정의한데이터타입인경우 ( 즉, MFC에서제공하지않는데이터타입의경우 ) 에사용 #include "stdafx.h" #include "Console.h" #include <afxtempl.h> CWinApp theapp; using namespace std; // 템플렛클래스사용을위해필요 struct Point3D int x, y, z; Point3D() // 템플렛의경우반드시기본생성자가필요 Point3D(int x0, int y0, int z0) x = x0; y = y0; z = z0; ; 40
배열클래스 배열클래스 int _tmain(int argc, TCHAR* argv[ ], TCHAR* envp[ ]) int nretcode = 0; if (!AfxWinInit(...)) // 생략... // Point3D 객체를저장할수있는배열객체생성 CArray<Point3D, Point3D&> array; array.setsize(5); // 크기생성 for(int i=0; i<5; i++) Point3D pt(i, i*10, i*100); // x, y, z축의좌표값을동시에배열에저장 array[i] = pt; // 배열에 pt 대입 for(i=0; i<5; i++) Point3D pt = array[i]; cout << pt.x << ", " << pt.y << ", " << pt.z << endl; return nretcode; 41 42 리스트 Linked List 동일한데이터타입의데이터를포인터를이용하여연결시킨자료구조 장점 원소의삽입과삭제가포인터조작만으로가능하기때문에빠르다 단점 특정위치에있는원소를참조시, 리스트의처음또는끝에서시작해서포인터를따라가야하므로속도가느려진다 리스트클래스 MFC 리스트클래스 양방향포인터를가지는이중연결리스트로구현 Head 템플릿클래스 afxtempl.h 헤더파일 Tail 클래스이름 데이터타입 사용예 CList 프로그래머가결정 CList<CPoint, CPoint&> list; 43 44
리스트클래스 비템플릿클래스 afxcoll.h 헤더파일 리스트클래스 생성과초기화 - 비템플릿 클래스이름 CObList CPtrList 데이터타입 CObject 포인터 void 포인터 사용예 CObList list; CPtrList list; char *szfruits[ ] = " 사과 ", " 딸기 ", " 포도 ", " 오렌지 ", " 자두 " ; CStringList CString CStringList list; CStringList list; // 리스트객체생성 for(int i=0; i<5; i++) list.addtail(szfruits[i]); // AddHead() 또는 AddTail() 을호출하여원소를 // 리스트의앞이나뒤에추가 45 46 리스트클래스 순환 // 리스트제일앞에서출발하여순환한다 POSITION pos = list.getheadposition(); // 리스트의시작위치를얻고 while(pos!= NULL) CString string = list.getnext(pos); // 차례로데이터에접근 cout << (LPCTSTR)string << endl; cout << endl; // 리스트제일뒤에서출발하여순환한다 pos = list.gettailposition(); // 리스트의끝위치를얻고 while(pos!= NULL) CString string = list.getprev(pos); // 차례로데이터에접근 cout << (LPCTSTR)string << endl; 47 리스트클래스 항목삽입과삭제 // POSITION 타입의변수 pos는이전의예제에서선언한것이다. pos = list.find(" 포도 "); // 데이터의위치를얻음 list.insertbefore(pos, " 살구 "); // pos 위치앞쪽에데이터삽입 list.insertafter(pos, " 바나나 "); // pos 위치뒤쪽에데이터삽입 list.removeat (pos); // pos 위치데이터삭제 // 항목삽입과삭제후결과를확인한다. pos = list.getheadposition(); while(pos!= NULL) CString string = list.getnext(pos); cout << (LPCTSTR)string << endl; 48
리스트클래스 리스트클래스 템플릿리스트클래스 #include "stdafx.h" #include "Console.h" #include <afxtempl.h> CWinApp theapp; using namespace std; struct Point3D int x, y, z; Point3D() Point3D(int x0, int y0, int z0) x = x0; y = y0; z = z0; ; int _tmain(int argc, TCHAR* argv[ ], TCHAR* envp[ ]) int nretcode = 0; if (!AfxWinInit(...)) // 생략... CList<Point3D, Point3D&> list; for(int i=0; i<5; i++) list.addtail(point3d(i, i*10, i*100)); POSITION pos = list.getheadposition(); 49 50 리스트클래스 맵클래스 맵동작원리 while(pos!= NULL) Point3D pt = list.getnext(pos); cout << pt.x << ", " << pt.y << ", " << pt.z << endl; 키데이터해시함수 데이터 return nretcode; MFC 맵클래스구현 키 데이터 51 키데이터키데이터키데이터 키데이터키데이터 52
맵클래스 템플릿클래스 afxtempl.h 헤더파일 맵클래스 비템플릿클래스 afxcoll.h 헤더파일 클래스이름 키 데이터 사용예 클래스이름 데이터타입 사용예 CMapWordToOb WORD CObject 포인터 CMapWordToOb map; CMap 프로그래머가결정 CMap<CString, CString&, CPoint, CPoint&> map; CMapWordToPtr CMapPtrToWord WORD void 포인터 void 포인터 WORD CMapWordToPtr map; CMapPtrToWord map; CMapPtrToPtr void 포인터 void 포인터 CMapPtrToPtr map; CMapStringToOb 문자열 CObject 포인터 CMapStringToOb map; CMapStringToPtr 문자열 void 포인터 CMapStringToPtr map; CMapStringToString 문자열 문자열 CMapStringToString map; 53 54 맵클래스 맵클래스 생성, 초기화, 검색 순환 CMapStringToString map; map[" 사과 "] = "Apple"; map[" 딸기 "] = "Strawberry"; map[" 포도 "] = "Grape"; map[" 우유 "] = "Milk"; // 사과 키에 Apple 데이터추가 CString str; if(map.lookup(" 딸기 ", str)) // 딸기 키로데이터검색 cout << " 딸기 -> " << (LPCTSTR)str << endl; POSITION pos = map.getstartposition(); // 시작위치얻기 while(pos!= NULL) CString strkey, strvalue; map.getnextassoc(pos, strkey, strvalue); // 다음키와데이터얻기 cout << (LPCTSTR)strKey << " -> " << (LPCTSTR)strValue << endl; 55 56
맵클래스 삽입과삭제 map.removekey(" 우유 "); map[" 수박 "] = "Watermelon"; // 우유 키와데이터를삭제 // 수박 키와 Watermelon 데이터추가 // 항목삽입과삭제후결과를확인 // POSITION 타입의변수 pos 는이전의예제에서선언한것 pos = map.getstartposition(); while(pos!= NULL) CString strkey, strvalue; map.getnextassoc(pos, strkey, strvalue); cout << (LPCTSTR)strKey << " -> " << (LPCTSTR)strValue << endl; 맵클래스 템플릿맵클래스 #include "stdafx.h" #include "Console.h" #include <afxtempl.h> CWinApp theapp; using namespace std; UINT AFXAPI HashKey(CString& str) LPCTSTR key = (LPCTSTR) str; UINT nhash = 0; while(*key) nhash = (nhash<<5) + nhash + *key++; return nhash; 57 58 맵클래스 맵클래스 int _tmain(int argc, TCHAR* argv[ ], TCHAR* envp[ ]) int nretcode = 0; if (!AfxWinInit(...)) // 생략... CMap<CString, CString&, UINT, UINT&> map; map[cstring (" 사과 ")] = 10; map[cstring (" 딸기 ")] = 25; map[cstring (" 포도 ")] = 40; map[cstring (" 수박 ")] = 15; 59 UINT ncount; if(map.lookup(cstring(" 수박 "), ncount)) cout << " 수박 " << ncount << " 상자가남아있습니다." << endl; return nretcode; 60