728x90
반응형

타입 변환 예시

이전 내용에서 암시적 타입 변환을 지원하는 것은 좋지 않다.라는 내용을 기억할 수 있다.

하지만 가장 흔한 예외 중 하나가 숫자 타입을 만들 때이다.

예를 들어 유리수를 나타내는 클래스를 만들고 있다면, 정수에서 유리수로의 암시적 변환은 허용하자고 판단하더라도 크게 이상하지 않다.

아래의 예시를 봐보면,

class Rational
{
public:
    	Rational(int numerator = 0, int denominator = 1); // 암시적 변환을 위해 explicit를 붙이지 않음.
        int numerator() const;
        int denominator() const;
        
private:
	....
};

위의 클래스는 int에서 Rational로의 암시적 변환을 허용한다. 이 클래스에서 기본 연산(*,+,-,/ 등..)을 지원하기 위해서는 멤버 함수 or 비멤버 함수 or 비멤버 프랜드 함수 중 어떤 것을 선택하는지 좋을까?

 

먼저 operator*를 멤버 함수로 선언했을 때를 봐보자.

class Rational
{
 public:
  ...
  const Rational operator*(const Rational& rhs)const;
};

Rational oneEnglish(1,8);
Rational oneHalf(1,2);
 
Rational result = oneHalf * oneEnglish; // OK! 
result = result * oneEighth; // OK!

result = oneHalf * 2; // OK!
result = 2 * oneHalf; // Error!

위의 코드에서 아래의 두 연산을 풀어쓰면

result = oneHalf.operator*(2); // result = oneHalf * 2
result = 2.operator*(onehalf); // result = 2 * oneHalf

가 되는데, 2에는 클래스가 연관되지 않았기에 operator를 호출할 수 없게 된다.

즉, 혼합형 수치 연산을 지원하지 못하게 된다.

 

그렇다면 'oneHalf * 2'는 왜 에러가 발생하지 않을까? 분명 operator*연산의 매개변수로는 Rational을 받고 있는데 2를 대입해서 넣어줘도 제대로 동작을 하고 있다.

이는 바로 암시적 타입 변환에 의해서 일어나는데, 컴파일러가 함수에 int를 넘겨받았지만 Rational을 요구한다는 것을 알고 아래처럼 int를 Rational클래스 생성자에 넣고 호출하여 Rational로 둔갑시킨 것이다.

const Rational temp(2); 
result = oneHalf * temp;

물론 생성자에 명시 호출(explicit)을 해줬다면 'oneHalf * 2'도 에러가 떴을 것이다.

 

결과적으로 암시적 타입 변환에 대해 매개변수가 먹히려면 매개변수 리스트에 있어야 하며, 호출되는 멤버 함수를 갖고 있는(this가 가리키는) 객체에 해당하는 암시적 매개변수에는 암시적 변환이 먹히지 않는다.

 

이 문제를 해결하기 위해서 operator*를 비멤버 함수로 만들어 컴파일러 쪽에서 모든 인자에 대한 암시적 타입 변환을 수행하도록 하면 혼합형 수치 연산을 지원할 수 있다.

const Rational operator*(const Rational& lhs, const Rational& rhs)
{
    return Rational(lhs.numerator() * rhs.numerator(),
    lhs.denominator() * rhs.denominator();
}
 
Rational oneFourth (1,4);
Rational result;
 
result = oneFourth * 2; // OK!
result = 2 * oneFourth; // OK!

그리고 기억해야 할 것은 멤버 함수의 반대는 프랜드 함수가 아니라 비멤버 함수라는 것이다.

 

요약

  • 어떤 함수에 들어가는 모든 매개변수(this 포인터가 가리키는 객체도 포함해서)에 대해 타입 변환을 해줄 필요가 있다면, 그 함수는 비멤버여야 한다.
728x90
반응형