일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 오블완
- lua
- 루아
- UE4
- virtual function
- operator new
- Vector
- 영화 리뷰
- effective stl
- 비교 함수 객체
- exception
- 스마트 포인터
- reference
- 메타테이블
- more effective c++
- Smart Pointer
- 티스토리챌린지
- resource management class
- 게임
- 암시적 변환
- 다형성
- 상속
- implicit conversion
- Effective c++
- 참조자
- 반복자
- 예외
- 영화
- c++
- 언리얼
Archives
- Today
- Total
스토리텔링 개발자
[Effective C++] 24. 비멤버 함수 구현으로 암시적 변환 지원 본문
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 형태가 실패한 이유
- 정수 2에는 operator* 멤버 함수가 있을리 없다.
- 컴파일러는 호출할 수 있는 미멤버 버전의 operator*(네임스페이스 혹은 전역 유효 범위에 있는 operator*)도 찾아본다.
- 하지만 operator*(int, Rational) 형태의 비멤버 함수가 없으므로 에러가 발생한다.
- oneHalf * 2 형태가 성공한 이유
- Rational::operator*는 인자로 Rational 객체를 받을 뿐인데 어떻게 성공했을까.
- 컴파일러는 Rational::operator* 함수를 사용함을 인지한다.
- 또한 컴파일러는 int를 Rational 클래스의 생성자에 주어 호출하면 Rational로 변환할 수 있다는 사실도 안다.
- 그러므로 아래 코드처럼 동작했다.
-
const Rational temp(2); result = oneHalf * temp;
- 당연하지만, 이 암시적 변환은 명시호출(explicit)로 선언되지 않은 생성자였기에 가능했다.
- Rational::operator*는 인자로 Rational 객체를 받을 뿐인데 어떻게 성공했을까.
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 참조)
참조
728x90
'개발 > Effective C++' 카테고리의 다른 글
[Effective C++] 26. 필요한 시점 직전에 변수를 정의할 것 (0) | 2024.06.20 |
---|---|
[Effective C++] 25. 예외를 던지지 않는 swap 함수 (0) | 2024.06.19 |
[Effective C++] 23. 비멤버 비프렌드 함수 (0) | 2024.06.18 |
[Effective C++] 22. 데이터 멤버 확실히 숨기기 (0) | 2024.06.17 |
[Effective C++] 21. 참조자를 리턴하면 안되는 상황 (1) | 2024.06.14 |
Comments