스토리텔링 개발자

[Effective C++] 24. 비멤버 함수 구현으로 암시적 변환 지원 본문

개발/Effective C++

[Effective C++] 24. 비멤버 함수 구현으로 암시적 변환 지원

김디트 2024. 6. 18. 10:54
728x90

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

 

 

 

  • 클래스에서 암시적 타입 변환을 지원하는 것은 일반적으로 안 좋은 생각이다.
  • 다만, 숫자 타입은 C++ 기본 암시적 변환과 별반 다르지 않으므로 허용해도 좋을 것이다.

 

 

 

클래스 멤버 함수에서 사칙 연산 구현
class Rational // 유리수 클래스
{
public:
    Rational(int numerator = 0, int denominator = 1);
    // explicit을 붙이지 않은 이유는
    // int에서 Rational 암시적 변환을 허용하기 위함
    
    int numerator() const;
    int denominator() const;
    
public:
    const Rational operator*(const Rational& rhs) const;
    // 유리수의 곱셈
private:
    ...
};
  • 하지만 이 경우 대응이 되지 않는 연산이 존재한다.
Rational oneEighth(1, 8);
Rational oneHalf(1, 2);

// 암시적 변환이 없는 예시
Rational result = oneHalf * oneEighth; // OK
result = result * oneEighth; // OK

// 암시적 변환 예시
result = oneHalf * 2; // OK, 2가 암시적 변환이 되었다.

// 암시적 변환 실패 예시
result = 2 * oneHalf; // 에러!!!!
  • 2 * oneHalf 형태가 실패한 이유
    1. 정수 2에는 operator* 멤버 함수가 있을리 없다.
    2. 컴파일러는 호출할 수 있는 미멤버 버전의 operator*(네임스페이스 혹은 전역 유효 범위에 있는 operator*)도 찾아본다.
    3. 하지만 operator*(int, Rational) 형태의 비멤버 함수가 없으므로 에러가 발생한다.
  • oneHalf * 2 형태가 성공한 이유
    • Rational::operator*는 인자로 Rational 객체를 받을 뿐인데 어떻게 성공했을까.
      1. 컴파일러는 Rational::operator* 함수를 사용함을 인지한다.
      2. 또한  컴파일러는 int를 Rational 클래스의 생성자에 주어 호출하면 Rational로 변환할 수 있다는 사실도 안다.
    • 그러므로 아래 코드처럼 동작했다.
    • const Rational temp(2);
      result = oneHalf * temp;
    • 당연하지만, 이 암시적 변환은 명시호출(explicit)로 선언되지 않은 생성자였기에 가능했다.

 

 

 

2 * oneHalf 형태를 지원해보자
  • 문제점
    • 호출되는 멤버 함수를 갖고 있는 객체(this)에 대해서는 암시적 변환이 동작하지 않는다.
  • 해결법
    • operator* 를 비멤버 함수로 만들어 모든 인자에 대해 암시적 타입변환을 지원하면 된다.
class Rational
{
    ... // 멤버 operator*가 없다.
};

// 비멤버 함수로 구현한다.
const Rational operator*(const Rational& lhs, const Rational& rhs)
{
    return Rational(lhs.numerator() * rhs.numerator(),
                    lhs.denomitator() * rhs.denomitator());
}
  • 위 해결법에서 유의할 점
    • 위의 코드는 비공개된 멤버 변수를 getter로 지원하여 비프렌드 비멤버 함수로 구현할 수 있었다.
    • 비멤버 함수는 friend 함수로 할 필요가 없다면 하지 말도록 하자.

 

 

 

  • 클래스 템플릿으로 만들면 전혀 새로운 고민을 해야한다.(항목 46 참조)

 

 

 

참조
 

[More Effective C++] 5. 암시적 타입 변환 지양하기

항목 5. 사용자 정의 타입 변환 함수에 대한 주의를 놓지 말자   암시적 변환C처럼 C++ 역시 암시적 변환을 지원한다.예컨대 char -> int, short -> double 로 군소리 없이 변환시켜 준다.심지어 int -> shor

delightlane.tistory.com

 

728x90
Comments