C++언어는 C언어를 포함하므로 C언어의 형변환을 사용할 수 있지만 C++언어 자체의 형변환 연산자를 제공합니다.
(EC++에서 C스타일의 형변환보다는 C++ 스타일의 형변환을 사용하라고 권장합니다. C++ 스타일의 형변환을 사용하면 잘못된 형변환의 위험에서 좀 더 안전하며 설계자의 의도를 좀 더 확실히 할 수 있습니다.)
-
( ) C언어의 형변환 : 만능 형변환 = 무식한 형변환 = 불가능은 없다.
- 컴파일 타임 형변환 -
-
static_cast : 상식적인?! 형변환입니다. 여기서 상식적인 형변환이라 말한 이유는 상식적으로 생각했을 때 가능할 것 같은 형변환이기 때문입니다.(암시적 변환이 가능한 형변환을 명시적으로 변환한다든지, 수치적인 자료형을 변환한다든지, void*을 원형으로 변환할 때 사용합니다.) - 컴파일 타임 형변환 -
-
const_cast : C++ 스타일 형 변환에서 유일하게 const를 깨는 형 변환 연산자입니다.
- 컴파일 타임 형변환 -
-
reinterpret_cast : C++ 스타일의 형변환에서 가장 무식한 형변환입니다. const만 깰 수 없고 C언어의 형변환처럼 모두 가능합니다. 구현 환경(implementation)에 의존적이며 사용할 일이 거의 없습니다. - 컴파일 타임 형변환 -
-
dynamic_cast : 실행시간에 부모 형식을 자식 형식으로 다운캐스팅(downcasting) 할 때 사용합니다. - 런 타임 형변환 -
1, static_cast 연산자
static_cast는 컴파일 시간에 일반적으로 이루어지는 형변환에 사용됩니다.
명식적인 형변환에 사용합니다.
using namespace std;
void main( )
{
int n = 10;
double d = 3.5;
cout << n << ", " << d << endl;
n = d; //암시적 형변환
cout << n << ", " << d << endl;
n = (double)d; // C 스타일의 명시적 형변환
cout << n << ", " << d << endl;
n = static_cast<double>(d); //C++ 스타일의 명시적 형변환
cout << n << ", " << d << endl;
}
- 10, 3.5
3, 3.5
3, 3.5
3, 3.5
정수와 실수의 기본 타입인 int와 double 사이의 형변환입니다.
void*의 형변환에 사용합니다.
using namespace std;
void main( )
{
int n = 10;
void *pv = &n;
cout << *(int*)pv << endl; // C 스타일 형변환
cout << *static_cast<int*>(pv) << endl; // C++ 스타일 형변환
}
- 10
10
int*를 double*로 형변환은 불가능합니다.
using namespace std;
void main( )
{
double *pd = 0;
int n = 10;
pd = (double*)&n; // C스타일의 형변환 가능
pd = static_cast<double*>(&n); // C++ 스타일의 형변환 불가능 에러~~
}
- 에러~
int*를 double*로 변환은 의미 없는 변환이므로 static_cast는 잘못된 형변환으로 컴파일러가 인식합니다.
부모형을 자식형으로 형변환에 사용합니다.
using namespace std;
class Parent
{
};
class Child : public Parent
{
};
void main( )
{
Parent *p = new Child;
(Child*) p; // C 스타일 형변환
static_cast<Child*>(p); // C++ 스타일 형변환
}
- 출력 없음.
당연히 가능합니다.
또 하나 부모 형식을 자식 형식으로 형변환합니다. <= 잘못된 형변환 예제입니다.
using namespace std;
class Parent
{
};
class Child1 : public Parent
{
};
class Child2 : public Parent
{
};
void main( )
{
Parent *p = new Child1;
(Child2*) p; // C 스타일 형변환
static_cast<Child2*>(p); // C++ 스타일 형변환
}
- 출력 없음.
p는 Child1객체를 가지고 있지만 형변환을 Child2로 하고 있습니다. 컴파일 시간에는 p가 어떤 객체를 가지고 있는지 알지 못하므로 static_cast를 사용하면 위 내용은 문제 없이 컴파일됩니다. 그래서 버그가 만들어 지는 것이지요. 위 내용은 danamic_cast를 사용하여 해결할 수 있습니다.
2, const_cast 연산자
const_cast는 const를 비const화 할 때 사용합니다. 비 const화 할 수 있는 능력의 형변환은 const_cast 뿐입니다.
const 객체를 비 const 객체로 변환하는 예제입니다.
#include <iostream>
using namespace std;
class Point
{
int x, y;
public :
Point(int _x=0, int _y=0):x(_x),y(_y)
{
}
void Print( )
{
cout << x << ", " << y << endl;
}
};
void PrintPoint(const Point & arg)
{
// arg.Print() <= 형변환하지 않으면 호출할 수 없습니다. 멤버 함수 Print()가 const함수가 아니므로...
const_cast<Point&>(arg).Print( ); // <= arg를 비 const 객체로 변환하여 호출합니다.
}
void main( )
{
Point p1(2,3);
PrintPoint( p1 );
}
- 2, 3
const 객체인 arg를 비 const 객체로 변환하여 함수를 호출합니다. 위 코드는 예제를 보이기 위함으로 Print()함수는 당연히 const 함수여야 합니다.
만약 소스 코드를 수정할 수 없는 경우나 라이브러리 내에 들어있는 함수가 비 const 함수이고 const 객체로 함수를 호출해야한다면 const_cast를 사용해야 합니다.
const 포인터를 비 const 포인터로 변환하는 예제입니다.
using namespace std;
class Point
{
int x, y;
public :
Point(int _x=0, int _y=0):x(_x),y(_y)
{
}
void Print( )
{
cout << x << ", " << y << endl;
}
};
void PrintPoint(const Point *pArg)
{
const_cast<Point*>(pArg)->Print( ); // pArg를 비 const로 변환합니다.
}
void main( )
{
Point p1(2,3);
PrintPoint( &p1 );
}
- 2, 3
위 예제와 같습니다. 패~스!
3, reinterpret_cast 연산자
reinterpret_cast는 구현 환경마다 다르게 동작하고 C 스타일의 형변환처럼 무식한 형변환 연산자입니다.
아래는 무식한 예제입니다.
#include <iostream>
using namespace std;
class Point
{
int x, y;
public :
Point(int _x=0, int _y=0):x(_x),y(_y)
{
}
void Print( )
{
cout << x << ", " << y << endl;
}
};
void main( )
{
int n = 10;
reinterpret_cast<Point&>(n); // 오~~ 가능..
reinterpret_cast<Point*>(&n); // 오오~~ 가능..
reinterpret_cast<Point&>(n).Print();// 오오오~~ 가능..
reinterpret_cast<Point*>(n)->Print();// 오오오오~~ 가능.. ㅡㅡ;
}
- ㅡㅡ;
설명이 필요 없습니다. 할말이 없다는...
그렇다면 reinterpret_cast 연산자는 어디에 쓰는 것일까요? 쓰지 않는게 좋지만 꼭 써야하는 경우도 있습니다.
#include <iostream>
using namespace std;
void main( )
{
int n = 0x44434241;
char *pc = 0;
pc = reinterpret_cast<char*>(&n);
cout << pc[0] << endl;
cout << pc[1] << endl;
cout << pc[2] << endl;
cout << pc[3] << endl;
}
- A
B
C
D
명확히 강제 형변환을 의도했을 때입니다. 위 예제처럼 정수는 byte 단위로 접근한다든지, 네트워크 패킷의 임의 테이터에 접근하는 경우 등입니다.
4, dynamic_cast 연산자
dynamic_cast는 실시간에 형검사를 하거나 형변환할 때 사용합니다.
다형성을 지원하기 위해 부모 형식을 자식 형식으로 다운 캐스트하고 형식을 검사합니다.
using namespace std;
class Parent
{
public:
virtual void Print( ) = 0;
};
class Child1 : public Parent
{
public:
void Print( ) { cout << "class Child1" << endl; }
};
class Child2 : public Parent
{
public:
void Print( ) { cout << "class Child2" << endl; }
};
void main( )
{
Parent *p = new Child1;
Child1 *pChild1 = dynamic_cast<Child1*>(p);
if( NULL == pChild1 )
cout << "Child1 객체가 아닙니다." <<endl;
else
pChild1->Print();
Child2 *pChild2 = dynamic_cast<Child2*>(p);
if( NULL == pChild2 )
cout << "Child2 객체가 아닙니다." <<endl;
else
pChild2->Print();
}
- class Child1
Child2 객체가 아닙니다.
dynamic_cast는 실행 시간에 형변환하여 형변환이 불가능하면 NULL을 반환하고 가능하면 변환합니다. 주의할 점은 다형적인 객체에만(virtual 함수를 포함하는 클래스 객체) dynamic_cast를 사용할 수 있습니다. 당연한 이유로 dynamic_cast는 실행 시간에 정확한 객체 형식을 구분하여 인터페이스를 사용하기 위한(멤버 함수를 호출하기 위한) 목적으로 사용되기 때문입니다.
레퍼런스 예제입니다.
using namespace std;
class Parent
{
public:
virtual void Print( ) = 0;
};
class Child1 : public Parent
{
public:
void Print( ) { cout << "class Child1" << endl; }
};
class Child2 : public Parent
{
public:
void Print( ) { cout << "class Child2" << endl; }
};
void main( )
{
Child1 child;
Parent &parent = child;
try{
dynamic_cast<Child1&>(parent).Print();
}
catch( bad_cast &e)
{
cout << e.what() << endl;
}
try{
dynamic_cast<Child2&>(parent).Print();
}
catch( bad_cast &e)
{
cout << e.what() << endl;
}
}
- class Child1
Bad dynamic_cast!
dynamic_cast는 실행 시간에 형변환하여 형변환이 불가능하면 bad_cast을 throw하고 가능하면 변환합니다.
'Windows Developer > C++' 카테고리의 다른 글
[C++]STL에 대해서(보충) (0) | 2010.08.01 |
---|---|
[C++] 초기화 리스트(Initialize List) (1) | 2010.07.26 |
[C++] 가상함수 (0) | 2010.07.26 |
[C++]템플릿(template) (0) | 2010.07.20 |
[C++]STL 표준 C++ 라이브러리 (0) | 2010.07.20 |