이번에는 C++언어에서 제공하는 형 변환에 관해 살펴보기로 해요.
이 부분은 OOP 특징은 아니지만 앞에서 dynamic_cast를 사용하는 방법을 소개하여 다른 형 변환도 알아보려는 거예요.
먼저 C++ 언어에서도 강제 형변환(명시적 형변환이라고도 부름)을 제공하고 있습니다. 하지만 강제 형변환은 잘못 사용하면 심각한 버그를 유발할 수 있습니다.
다음은 서로 관련이 없는 Man 클래스와 Student 클래스를 정의한 후에 강제 형변환을 사용하는 예제입니다. 컴파일 오류는 발생하지 않지만 프로그램 동작 중에 버그로 런 타임 오류가 발생할 수 있습니다.
//강제 형 변환이 갖는 위험 요소
#include <iostream>
#include <string>
using namespace std;
class Man
{
string name;
public:
Man(string name)
{
this->name = name;
}
void View()const
{
cout<<"이름:"<<name<<endl;
}
};
class Student
{
int num;
string name;
public:
Student(int num, string name)
{
this->num = num;
this->name = name;
}
void View()const
{
cout<<"번호:"<<num<<"이름:"<<name<<endl;
}
};
int main()
{
Student *stu = new Student(30,"홍길동");
Man *man = (Man *)stu; //강제 형변환
man->View();
delete stu;
return 0;
}
C++에서는 보다 엄격하게 형 변환할 수 있는 방법을 제공하고 있습니다. 앞에서 다루었던 dynamic_cast는 일반화 관계에서 하향 캐스팅을 제공했었죠.
이 외에 static_cast, const_cast, reinterpret_cast를 제공하고 있습니다.
먼저 static_cast는 C언어의 강제 형변환과 유사합니다. 기반 클래스와 파생 클래스 사이의 형 변환 뿐만 아니라 기본 자료 형식 사이에서도 형 변환을 할 수 있습니다. 하지만 이에 관한 모든 책임은 개발자에게 있다는 것을 잊지 마세요.
다음은 하향 캐스팅을 dynamic_cast를 이용하지 않고 static_cast를 이용하였습니다. dynamic_cast를 사용하려면 가상 메서드를 갖고 있어야 하지만 static_cast는 가상 메서드를 갖고 있지 않아도 가능합니다.
//static_cast
#include <iostream>
#include <string>
using namespace std;
class Man
{
string name;
public:
Man(string name)
{
this->name = name;
}
void View()const
{
cout<<"이름:"<<name<<endl;
}
};
class Student:public Man
{
int num;
string name;
public:
Student(int num, string name):Man(name)
{
this->num = num;
this->name = name;
}
void View()const
{
cout<<"번호:"<<num<<"이름:"<<name<<endl;
}
void Study()
{
cout<<name<<" 공부하다."<<endl;
}
};
int main()
{
Man *man = new Student(30,"홍길동");
Student *stu = static_cast<Student *>(man);
stu->Study();
delete man;
return 0;
}
▷ 실행 결과
홍길동 공부하다.
다음은 기본 형식 사이에 static_cast를 사용한 예제입니다.
//기본 형식 간에 static_cast
#include <iostream>
using namespace std;
int main()
{
int a = 3;
double d;
d = static_cast<double>(a);
cout<<d<<endl;
return 0;
}
▷ 실행 결과
3
하지만 언제나 static_cast를 할 수는 없습니다. 예를 들어 string 형식과 int 형식 사이에서는 static_cast를 할 수 없습니다.
//static_cast 를 할 수 없는 예
#include <iostream>
#include <string>
using namespace std;
int main()
{
int a = 3;
string name;
name = static_cast<string>(a);//형 변환 오류
cout<<name<<endl;
return 0;
}
static_cast는 다양한 형태에서 형 변환을 할 수 있지만 모든 책임은 개발자의 몫임을 항상 잊지 마세요.
이번에는 const_cast를 알아봅시다.
const 포인터 변수는 가리키는 값을 변경할 수 없죠. const_cast는 const 포인터 변수가 가리키는 값을 변경할 수 있게 형 변환합니다. 만약 값을 변경하지 않겠다는 의미로 const 포인터 변수를 입력 인자로 받은 후에 const_cast로 값을 변경할 수 있다는 것입니다. 이러한 사용은 프로그램의 신뢰성이 떨어질 수 있습니다.
//const_cast
#include <iostream>
using namespace std;
void View(const int *input)
{
int *temp = const_cast<int *>(input);
*temp = 9;
cout<<"=== 가리키는 값 출력 ==="<<endl;
cout<<"*temp:"<<*temp<<endl;
cout<<"*input:"<<*input<<endl;
}
int main()
{
int value = 10;
View(&value);
return 0;
}
▷ 실행 결과
=== 가리키는 값 출력 ===
*temp:9
*input:9
마지막으로 reinterpret_cast를 알아봅시다. reinterpret_cast는 강제 형변환처럼 거의 모든 형 변환을 가능하게 해 줍니다. 예를 들어 flat * 를 int *로 형 변환을 요청하는 것을 허용합니다. 이러한 변환에서는 형 변환한 곳의 값을 float 형식이 아닌 int이라고 해석하여 값을 출력합니다.
다음은 float 형식 변수 -12.625가 메모리에 어떻게 기록하는지 확인하기 위해 reinterpret_cast를 사용한 예제 코드입니다.
//reinterpret_cast
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main()
{
float f=-12.625;
float *pf = &f;
int *a;
a = reinterpret_cast<int *>(pf);
cout<<hex<<(*a)<<endl;
return 0;
}
▷ 실행 결과
c14a0000
dynamic_cast는 다형성이 갖는 단점을 해결하기 위해 사용하지만 다른 형 변환은 극약 처방이 필요한 응급 상황이 아니면 사용을 자제해 주세요.
'언어 자료구조 알고리즘 > 디딤돌 C++' 카테고리의 다른 글
[C++] 43. 상속과 다형성 최종 실습 - 파생 클래스 (0) | 2016.04.25 |
---|---|
[C++] 42. 상속과 다형성 최종 실습 - 학생 (0) | 2016.04.25 |
[C++] 41. 상속과 다형성 최종 실습 시나리오 (0) | 2016.04.25 |
[C++] 40. 상속과 다형성 실습2 (도형) (0) | 2016.04.25 |
[C++] 39. 상속, 다형성 실습1 (상품, 할인 상품) (0) | 2016.04.25 |
[C++] 37. 하향 캐스팅(dynamic_cast) (0) | 2016.04.25 |
[C++] 36. 다중 상속 (0) | 2016.04.25 |
[C++] 35. 인터페이스 (INTERFACE) (0) | 2016.04.25 |
[C++] 34. 추상 클래스(ABSTRACT CLASS) (0) | 2016.04.25 |
[C++] 33. 메서드의 다형성 (virtual 키워드와 가상 메서드) (0) | 2016.04.25 |