서로 다른 데이터형이 호환이 되면 그 데이터형에 맞춰서 변환된다고 했다. 예를 들어
int value = 10.5; // double형이 int형으로 바뀜. 10으로 들어감.
double value2 = 5; // int형이 double형으로 바뀜. 5.0이 됨.
등이 있다. 호환되지 않는 데이터형은 자동으로 바뀌지 않는다.
int* p = 10; // 에러 발생.
하지만 강제적으로 바꿀 수는 있다.
int* p = (int*)10; // 강제로 바꿔서 가능.
이게 제대로 작동하는지는 또 다른 문제이다.
근데 이걸 클래스에서도 가능하다. 가령 이런 클래스가 있다고 해보자.
Stonewt.h
class Stonewt
{
private:
enum { Lbs_per_stn = 14 };
int stone;
double pds_left;
double pounds;
public:
Stonewt(double lbs);
Stonewt(int stn, double lbs);
Stonewt();
~Stonewt();
};
Stonewt.cpp
Stonewt::Stonewt(double lbs)
{
stone = int(lbs) / Lbs_per_stn;
pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);
pounds = lbs;
}
Stonewt의 클래스에는 double형 매개 변수를 받는 생성자가 있다. 이러면
Stonewt myCat;
myCat = 19.5; // 왠지 문법에 안 맞는 코드.
저런 신기한 코드가 있어도
값이 들어간다 ㄷㄷㄷㄷㄷ. 이런 과정이 자동적으로 일어나므로 '암시적 데이터형 변환'이라고 부른다. 이걸 실행해서 디버깅을 걸어보면,
이렇게 나오는데, 프로그램이 종료되지 않았는데도 객체가 생성되고 파괴된다. 왜? 7번 줄 구문에서, Stonewt(19.5) 생성자로 임시 객체가 생성되고 그걸 복사하는 식이기 때문이다. 하나의 매개변수를 받는 생성자만 이렇게 사용할 수 있다. 가령
Stonewt(int stn, double lbs);
이런 건 안된다. 근데 또 이런 경우는 두 번째 매개 변수에 디폴트 값이 설정되있으면 된다.
Stonewt(int stn, double lbs = 0);
하지만 이런 문구는 많이 쓰지 않는다. 헷갈리기 때문이다. 그래서 이런 암시적 데이터형 변환을 막는 문구도 있는데, 앞에 explicit을 붙이면 된다.
explicit Stonewt(double lbs);
지금까지 과정을 반대로 할 수 있을까? 가령
Stonewt myCat(283.2);
double value = myCat;
이런 건 가능할까? 가능하다. 하지만 이건 생성자를 사용하지 않고, 특별한 변환 함수를 이용해야 한다. 변환 함수는
operator typename();
이렇게 정의한다. 변환 함수의 특징은, 1. 클래스의 메서드여야 하고 2. 리턴형을 가지면 안되고 3. 매개 변수를 가지면 안된다. 예를 들어 double형으로 변환해주는 함수는
operator double();
이렇게 쓸 것이다. 함수 구문으로 일단 double형을 반환하는 걸 알았다. 그러니 리턴형을 쓸 필요가 없다. 변환 함수의 예를 보겠다.
Stonewt.h
class Stonewt
{
private:
...
public:
...
operator int() const;
};
Stonewt.cpp
Stonewt::operator int() const
{
return int(pounds + 0.5);
}
이런 식으로 작성할 수 있다. 근데 이게 쓰이긴 하나..?