[More Effective C++] 항목 5 ~ 6
항목 5 : 사용자 정의 타입 변환 함수에 대한 주의를 놓지 말자
- 사용자 타입에 암시적 타입 변환을 수행하기 위해 컴파일러가 사용하는 함수를 제공할지 말지 여부를 결정할 수 있다.
- 컴파일러가 사용 가능한 타입 변환 함수
- 단일 인자 생성자
- 암시적 타입변환 연산자
- 단일 인자 생성자 : 인자를 하나만 받아 호출하는 생성자
- 두 가지 방법 »1. 매개변수를 하나만 받도록 선언 »2. 매개변수가 여럿이지만 처음 걸 제외한 나머지가 모두 기본값을 갖도록 선언
- 암시적 타입 변환 연산자 : 타입 앞에 operator가 붙어있는 멤버함수. 반환값을 지정해 줄 수 없다.
- ex)
class Rational { public: operator double() const; };
- ex)
- 타입변환 함수들이 원하든 원하지 않든 호출되고 만다.
- ex)
Rational r(1, 2); cout << r;
- 해석 순서
- Rational 객체에 operator« 함수가 없음
- operator double()를 통해 암시적 타입 변환
- double의 operator«이 호출된다.
- 해결
- operator double을 똑같은 일을 하되 다른 이름을 갖는 함수로 바꿔치기 한다.
- 불편하지만 의도치 않은 잘못된 함수 호출을 막을 수 있다.
- string 클래스도 char*로의 암시적 변환 연산자 대신 c_str 메소드를 제공한다.
- 단일 인자 생성자를 통한 암시적 타입 변환은 더 까다롭다.
- ex)
template<class T> class Array { public: Array(int size); // 이걸 통해 암시적 변환이 가능하다. } if(a == b[i]) ... // a도 b도 Array객체이고, 원래라면 a[i] == b[i]여야 하지만 실수로 이렇게 작성했을 시.
- 해석 순서
- b[i]가 단일 생성자로 인해 암시적 타입 변환된다.(static_cast<Array
>(b[i])의 효과) - 단일 인자 생성자를 진짜로 제공해야 할 경우가 많으므로 피하기가 어렵다.
- b[i]가 단일 생성자로 인해 암시적 타입 변환된다.(static_cast<Array
- 해결
- explicit 키워드 사용 : 암시적 타입 변환을 막는다.
- ‘사용자 정의 타입 변환 함수는 두개 이상 동시에 쓰이지 않는다’ 규칙을 사용한다.
- ex) Array 템플릿에서 단일 생성자가 받는 int 인자를 대체할 ArraySize란 클래스를 제공한다. -> if(a == b[i])에서 int -> ArraySize -> Array 두 번의 타입 변환을 거쳐야 하기 때문에 에러가 발생하게 된다.
- Array
a(10)에서 10은 ArraySize의 단일 생성자로 타입 변환 되므로 성공한다. - ArraySize는 Array에서만 사용되므로 내부 클래스로 선언한다. 다른 사람이 쓸 수 있게 public으로 선언.
- 프록시 클래스 : 다른 객체를 대신하는 클래스(30)
- ex) ArraySize는 int를 대신한다.
- 다른 방법으로는 어찌할 수 없는 소프트웨어 동작식을 조정하는 데 요긴하다.
- 컴파일러가 맘대로 암시적 타입 변환을 하게 되면 득보다는 실이 많다.
- 타입 변환 연산자(함수)는 마음 깊은 곳에서 원하지 않는 이상 제공하지 말도록 하자!
항목 6 : 증가 및 감소 연산자의 전위 / 후위 형태를 반드시 구분하자
- 후위 형태는 int 타입의 인자를 받도록 하고 컴파일러는 후위 형태 증감 연산자가 호출될 때 0을 넘기도록 구현한다.
- 전위 / 후위를 구분하기 위함이다.
- 전위 증감 연산자 : 참조자 타입 리턴
- 후위 증감 연산자 : const 객체 타입 리턴
- 후위의 int 타입 매개변수는 내부적으로 사용되지 않는다.(전위와 후위의 구분용이다.)
- 후위 연산자가 const가 아닌 객체를 반환하길 꺼리는 이유
- 기본 제공 타입에 대한 증가 연산자 동작과 맞지 않는다.
- ex) int i; i++++; // 에러!
- 직관적이지 않고 헷깔린다.(사용자 편의를 위해)
- ex) i++++;가 허용이 되면 i는 한번만 증가한다.(후위 연산자는 임시 정수를 반환하기 때문이다.)
- 기본 제공 타입에 대한 증가 연산자 동작과 맞지 않는다.
- 후위 증감 연산자는 반환값으로 임시 객체를 만들어야 하므로 사용자 정의 타입을 가지고 작업할 때는 되도록 전위 증감 연산자가 좋다.
- 후위 증감 연산자는 반드시 전위 증감 연산자를 사용하여 구현할 것!
- 코드 유지(후위든 전위든 동작 방식이 같아야 함을 보장)가 편하기 때문.