본문 바로가기
C++/Effective C++

항목 24 타입 변환이 모든 매개변수에 대해 적용되어야 한다면 비멤버 함수를 선언하자

by 멍청이 개발자 2024. 1. 22.
반응형

자 이번 항목은 암시적 변환을 허용하는 클래스에 대한 내용이다. 우선 아래와 같은 타입의 클래스가 있다고 치자.

class Rational {
public:
    Rational(int numerator = 0, int denominator = 1);
    
    int numerator() const;
    int denominator() const;
private:
    ...
};

대충 분수를 나타내는 클래스이다. 우리는 여기서 각 Rational 과의 곱셈을 할 수 있도록 하기 위해서 operator*를 멤버함수로 만들수 있다.

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

자, 이렇게 되면 우리는 아래와 같은 식을 작성 할 수도 있다.

Rational oneEighth(1, 8);
Rational oneHalf(1, 2);

Rational result = oneHalf * oneEighth;
result = result * oneEighth;

자, 그런데 우리는 곱셈을 좀더 자연스럽게 하기위해 정수와의 곱셈도 허용하고 싶다. 그래서 우리는 아래와 같은 코드를 작성했다.

result = oneHalf * 2; // 정상 작동
result = 2 * oneHalf; // 오류!

하지만 두번째 줄에서 오류가 발생한다. 그 이유는 아래 코드를 보면 바로 이해 될 것이다.

result = oneHalf.operator*(2); // 정상 작동
result = 2.operator*(oneHalf); // 오류!

자, int의 operator*는 당연히 Rational 클래스에 대해서는 작동하지 않는다. 그렇다면 어떻게 해야 할까? 바로 비 멤버 함수를 만들어 버리는 것이다. 비멤버 함수로 선언한 후 2가 Rational로 암시적 변환이 된다면 정상 작동 할 것이다.

class Rational {
    ...
};

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;
result = 2 * oneFourth;

자, 그리고 여기서 한 가지 기억해야 할점은 멤버 함수의 반대는 프렌드 함수가 아니라 비멤버 함수라는 점이다. 프렌드를 통해 이점을 얻는 것보다 프렌드를 통해 골치 아픈 점이 더 많으니 유의 하도록 하자.

반응형