#. 내용
- dynamic_cast는 포인터끼리 또는 레퍼런스 끼리 변환할 때 사용되며, 변환시 규칙은 다음과 같습니다.
-> 포인터는 포인터로, 레퍼런스는 레퍼런스로 변환함.
-> 포인터끼리 변환할 때에도 반드시 상속 계층에 속한 클래스끼리만 변환할 수 있음.
- dynamic_cast는 부모 타입의 포인터를 자식의 포인터로 다운 캐스팅할 때 사용하며, 캐스팅할 때에도 무조건 변환을 혀옹하지 않고 안전하다고 판단될 때에만 허용합니다. dynamic_cast가 안전하다고 판단하는 경우는 변환 대상 포인터가 부모 클래스형 타입이고, 자식 객체를 가리키고 있을 때 이 포인터를 자식 클래스형 포인터로 다운 캐스팅 하는 경우에 허용합니다. 만약 변환 대상 포인터가 실제로 가리키는 대상이 부모 클래스의 객체라면 안전하지 않다고 판단하고 변환하지 않으며, 이럴 경우 null값을 반환합니다.
- 만약 포인터가 실제로 가리키는 대상이 기본 클래스의 객체라면 변환하지 않습니다.
#. 제약사항
- dynamic_cast 를 사용하기 위해서는 몃가지 제약사항이 있습니다. 제약 사항은 다음과 같습니다.
-> 상속 관계 안에서만 사용할 수 있다.
-> 하나 이상의 가상함수를 가지고 있어야 한다.
-> 컴파일러의 RTTI 설정이 켜져 있어야 한다.
#. 예제
#include <Turboc.h>
class Parent
{
public:
virtual void PrintMe() { printf("I am Parent\n"); }
};
class Child : public Parent
{
private:
int num;
public:
Child(int anum=1234) : num(anum) { }
virtual void PrintMe() { printf("I am Child\n"); }
void PrintNum() { printf("Hello Child=%d\n",num); }
};
void main()
{
Parent P,*pP,*pP2;
Child C,*pC,*pC2;
pP=&P;
pC=&C;
pP2=dynamic_cast<Parent *>(pC); // 업 캐스팅-항상 안전하다.
pC2=dynamic_cast<Child *>(pP2); // 다운 캐스팅-경우에 따라 다르다.
printf("pC2 = %p\n",pC2);
pC2=dynamic_cast<Child *>(pP); // 캐스팅 불가능
printf("pC2 = %p\n",pC2);
}
'MFC'에 해당되는 글 18건
- 2010.03.22 dynamic_cast
- 2010.03.22 OpenFile() 함수
- 2010.03.22 C 입출력 Format Specifier(%d, %s 등) 알아보기.
- 2010.03.22 한글이 포함된 문자열에서 특정문자 삭제하기.
- 2010.03.22 STL 컨테이너 맵 <std::map> 간략 정리.
- 2010.03.22 [Tip]컨트롤들의 탭 순서를 변경하는 방법.
- 파일 입출력을 위한 함수입니다. win 16bit 시절에 사용되던 함수로 32bit로 업그레이드 되면서 대폭 수정되었고 요즘은 거의 사용하지 않게 되었습니다. 하지만 호환성을 위해 32bit에서도 적용 가능합니다.
#. 원형
- HFILE OpenFile(LPCSTR lpFileName, LPOFSTRUCT lpReOpenBuff, UINT uStyle);
#. 파라미터
- lpFileName[in]: 오픈할 파일의 경로.
- lpOpenBuff[out]: openFile호출 후 열려있는 파일을 참조하는데 사용하는 OFSTURCT 구조에 대한 포인터를 반환 함.
- uStyle[in]: 오픈할 파일을 어떻게 사용할지 정함. 여러개 중복 가능.
-> OF_CREATE(파일을 새로 생성), OF_WRITE(쓰기 전용으로 파일 열기) 등이 있음.
#. 예제
- OpenFile(m_szPath, &osDest, OF_CREATE | OF_WRITE);
print(), sprintf(), fprintf(), 함수 속의 퍼센트(%) 기호들은 "Format Specifier"라고 하는데, 출력 형식을 지정하는 것이다. Format-specifier는 따옴표("")에 의해 둘러싸인 문자열 상수이다. Format-specifier의 내용 중에 %와 한 개의 문자로 이루어진 부분은 두 번째 이후의 인자들이 출력될 자리를 나타내고 그 나머지는 Format-specifier내에 적힌 내용을 한 문자도 변경하지 않고 그대로 출력한다.
Format-specifier 내에서 % 뒤에 따라오는 문자의 종류에 따라서 출력될 변수의 값을 표현하는 방식이 결정된다. 예를 들어, %d라고 표기하면 해당되는 인자는 정수로 출력되고, %c라고 표기하면 문자로 출력되는 식이다.(해당 변수의 갑을 1바이트 값으로 읽고 이를 ASCII값으로 해석한다.) 이에 대해 간단히 정리해 보자.
출처 : 몽키몽키님의 네이버 블로그
프로그램을 하다보면 문자열 처리시 문자열에 포함된 특정 문자를 제거해야하는 경우가 종종있습니다.
예를들어, 어떤 명칭을 입력받으면서 공백없이 입력해달라고 했는데 사용자의 실수로 공백이 같이 입력되면
처리하는쪽에서 문자열에 공백이 있는지 여부를 체크하고 공백이 있다면 해당 공백을 제거해야합니다.
MFC를 사용하다보면 문자열 처리시에 CString 클래스를 많이 사용하는데, CString 클래스의 멤버함수중에
Remove 라는 함수가 있고 이 함수가 CString이 관리하는 문자열에서 특정 문자를 제거하는 기능입니다.
예를들면, 아래와 같습니다.
CString str = "Hello World!!";
str.Remove(' ');
AfxMessageBox(str);
이렇게 하면 결과가 아래와 같이 문자열에 공백이 제거된 상태로 메시지박스에 출력됩니다.
HelloWorld
하지만, 여기에 문제가 있습니다. 이 CString 클래스자체가 한글을 기준으로 제작된 클래스가 아니라서
한글이 포함된 문자열인 경우 Remove 함수를 사용하면 원하지 않는 결과가 발생합니다.
한글코드가 "한글여부(1bit) + 초성(5bit) + 중성(5bit) + 종성(5bit) = 총 2바이트(16비트)"로 구성되기
때문에 영문기준으로 1바이트씩 문자열을 비교하다보면 "디", "바"와 같이 종성이 없거나 종과 같이 종성이
존재하는 경우라도 한글문자가 공백다음에 놓이면 문자열값이 변형되는 문제가 발생합니다.
변경전 CString::Remove(' ')를 이용하여 변경한 후...
"다 다" --> "다도"
"다 바" --> "다뭐"
"다 종" --> "다좋"
결국 조금 불편하더라도 한글이 포함된 문자열에서 특정 문자를 제거하는 경우에는 한글을 고려해서
문자열 처리가 될수 있도록 아래와 같이 함수를 구성해서 사용하는것이 좋습니다.
void www_tipssoft_com_RemoveCharFromString(CString &parm_string, char parm_remove_char)
{
int count = parm_string.GetLength(), index = 0;
if(count > 0){
// 문자열 제거에 사용할 버퍼를 생성한다. 이 버퍼는 기준 문자열보다 클 필요가 없다.
char *p_data = new char[count + 1];
for(int i = 0; i < count; i++){
if(parm_string[i] & 0x80){
// 한글인 경우는 2바이트로 구성되기 때문에 1바이트 정보인 parm_remove_char와 비교할
// 필요가 없다. 따라서 그냥 2바이트 정보를 모두 복사해주면 된다.
p_data[index++] = parm_string[i++];
p_data[index++] = parm_string[i];
} else {
// 한글이 아닌 경우는 정보가 1바이트씩 구성되기 때문에 parm_remove_char에 지정된
// 문자와 비교하여 다른 경우에만 복사한다.
if(parm_remove_char != parm_string[i]) p_data[index++] = parm_string[i];
}
}
// parm_remove_char를 뺀 나머지 문자가 복사된 문자열의 끝에 '\0'을 추가한다.
p_data[index] = 0;
// parm_remove_char가 제거된 문자열을 원본 문자열에 저장한다.
parm_string = p_data;
// 문자열 제거에 사용한 버퍼를 제거한다.
delete[] p_data;
}
}
사용방법 :
CString str = "이동 디스크";
www_tipssoft_com_RemoveCharFromString(str, ' ');
AfxMessageBox(str);
이렇게 하면 결과가 아래와 같이 문자열에 공백이 제거된 상태로 메시지박스에 출력됩니다.
( CString::Remove 함수를 사용하면 "이동도슬탤" 라고 출력됩니다. )
이동디스크
출처 : 팁스 소프트
http://www.tipssoft.com/bulletin/tb.php/FAQ/253
#. 설명.
- 다른 STL의 컨테이너 처럼 map은 많은 장점을 가진 유익한 컨테이너입니다. 빠른 Indexing을 위해서라면 STL의 컨테이너중 map을 가장 먼저 생각할 수 있겠습니다.
- map은 Associative Container (연관컨테이너)에 속하는데 Associative Container란 키를 가지고 sort된 후에 적재되는 컨테이너로 검색속도를 빠르게 하기 위한 목적을 가진 컨테이너 입니다. map은 정렬 연관 컨테이너이며, key와 value의 쌍으로 이루어진 자료구조입니다.
- 대부분 균형 이진 탐색 트리(balanced binary search tree)를 사용해 구현하며 추가/삭제에 O(log n)이 걸리며 검색에 있어서 탁월한 성능을 발휘합니다.
#. map의 특징에 대해서 간단히 살펴 보면 다음과 같습니다.
1. key와 value로 element를 관리할 수 있다.
2. key는 숫자 이외에도 문자열 순서를 가질 수 있는 (즉, 비교 연산자를 가지고 있는) 데이터 타입이면 모두 key가 될 수 있다.
3. key는 순서 (order)를 가지고 관리되기 때문에 검색이 빠르다.
4. key는 unique해야 한다.
5. aMapkey = value 와 같이 [] 연산자를 제공해준다.
6. Element가 추가/삭제 될 때 크기도 같이 확장 축소 된다.
#. 아래는 MSDN에 나와있는 샘플코드입니다. 참고하세요^^
Sample Code:
//////////////////////////////////////////////////////////////////////
//
// Compile options needed: None
//
// <filename> : main.cpp
//
// Functions:
//
// end
// find
// insert
//////////////////////////////////////////////////////////////////////
#pragma warning(disable:4786)
#include <iostream>
#include <string>
#include <map>
using namespace std;
typedef map<int, string, less<int> > INT2STRING;
void main()
{
// 1. Create a map of ints to strings
INT2STRING theMap;
INT2STRING::iterator theIterator;
string theString = "";
int index;
// Fill it with the digits 0 - 9, each mapped to its string counterpart
// Note: value_type is a pair for maps...
theMap.insert(INT2STRING::value_type(0,"Zero"));
theMap.insert(INT2STRING::value_type(1,"One"));
theMap.insert(INT2STRING::value_type(2,"Two"));
theMap.insert(INT2STRING::value_type(3,"Three"));
theMap.insert(INT2STRING::value_type(4,"Four"));
theMap.insert(INT2STRING::value_type(5,"Five"));
theMap.insert(INT2STRING::value_type(6,"Six"));
theMap.insert(INT2STRING::value_type(7,"Seven"));
theMap.insert(INT2STRING::value_type(8,"Eight"));
theMap.insert(INT2STRING::value_type(9,"Nine"));
// Read a Number from the user and print it back as words
for( ; ; )
{
cout << "Enter \"q\" to quit, or enter a Number: ";
cin >> theString;
if(theString == "q")
break;
// extract each digit from the string, find its corresponding
// entry in the map (the word equivalent) and print it
for(index = 0; index < theString.length(); index++){
theIterator = theMap.find(theString[index] - '0');
if(theIterator != theMap.end() ) // is 0 - 9
cout << (*theIterator).second << " ";
else // some character other than 0 - 9
cout << "[err] ";
}
cout << endl;
}
}
#. 위 소스의 출력화면 입니다.
Program Output is:
Enter "q" to quit, or enter a Number: 22
Two Two
Enter "q" to quit, or enter a Number: 33
Three Three
Enter "q" to quit, or enter a Number: 456
Four Five Six
Enter "q" to quit, or enter a Number: q
다이얼로그 박스가 띄워질 때 원하는 컨트롤에 커서가 깜빡이게 하고 싶은 경우 주로 사용합니다.
다이얼로그 리소스 편집 창에서 각 컨트롤들의 탭 순서를 변경하고 싶은 경우.
1. [Ctrl]+D를 누른다.
2. 각 컨트롤들의 탭 순서가 표시된다.
3. 첫번째 순서가 될 컨트롤부터 차례대로 마우스로 클릭한다.
4. 순서를 모두 변경했으면 다시한번 [Ctrl]+D를 누른다.
OnInitDialog()에서 컨트롤에 SetFocus를 주거나 PostMessage(WM_SETFOCUS)를 주는 방법도 있지만 이 방법이 가장 손쉬운 듯 합니다. 거의다 아시겠지만 뭐..약간의 팁이랄까요?^^;; 참고로 VS 6.0에서 활용할 수 있습니다.
VS2005에서는 다이얼로그 박스에서 해당 컨트롤의 속성창에서 TabIndex의 숫자를 변경하면 됩니다.^^