항목 25 : 예외를 던지지 않는 swap에 대한 지원도 생각해 보자 swap는 자기대입 현상의 가능성에 대처하기 위한 대표적인 메커니즘으로서 널리 사랑받아 왔습니다. 두 객체의 값을 '맞바꾸기'한다는 것은 각자의 값을 상대방에게 주는 동작입니다. 표준 swap가 동작시 복사가 세 번 일어납니다. 이런 복사가 일어날시 손해를 보는 타입들 중 으뜸을 꼽는다면 아마도 다른 타입의 실제 데이터를 가리키는 포인터가 주성분인 타입일 것입니다. 이러한 개념을 쓰고 있는 기법이 바로 pImpl입니다. 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 class WidgetImpl { public : ... private : int a, b, c; s..
항목 24 : 타입 변환이 모든 매개변수에 대해 적용되어야 한다면 비멤버 함수를 선언하자 유리수를 나타내는 클래스를 선언하겠습니다. 1 2 3 4 5 6 7 8 9 10 class Rational { public : Rational(int numerator = 0, int denominator = 1); // 생성자에 일부러 explicit를 붙이지 않았습니다. // int에서 Rational로의 암시적 변환을 허용하기 위해서 그런 것이죠. int numerator() const; // 분자 및 분모에 대한 접근용 함수입니다. int denominator() const; private : ... }; Colored by Color Scripter operator*을 Rational의 멤버 함수로 만들어 ..
항목 23 : 멤버 함수보다는 비멤버 비프렌드 함수와 더 까가워지자 웹브라우저를 나타내는 클래스가 하나 있다고 가정합시다. 웹브라우저 클래스라면 여러 기능을 제공하는 함수가 많을 것입니다. 캐시를 비우는 함수, URL의 기록을 없애는 함수, 쿠키를 전부 제거하는 함수등이 있겠죠. 1 2 3 4 5 6 7 8 class WebBrowser { public: ... void clearCache(); void clearHistory(); void removeCookies(); ... }; 하지만 사용자 중에는 이 세 동작을 한 번에 하고 싶은 분들도 있기 때문에, 세 함수를 모아서 불러주는 함수도 준비해 둘 수 있을 것입니다. 1 2 3 4 5 6 class WebBrowser { public: ... voi..
항목 22 : 데이터 멤버가 선언될 곳은 private 영역임을 명심하자 이번 항목에서는 데이터 멤버가 어째서 public이면 안 되는지에 대한 이유를 알아보고, public 데이터 멤버에 대한 모든 이야기가 protected 데이터 멤버에도 똑같이 적용되는 모습을 함께 확인하도록 하지요. public 데이터 멤버는 왜 안 될까요? 우선 문법적 일관성이 이유가 되겠습니다. 데이터 멤버가 public이 아니라면, 사용자 쪽에서 어떤 객체를 접근할 수 있는 유일한 수단은 멤버 함수일 것입니다. 그렇다면 그 클래스의 멤버에 접근하고 싶을 때 그냥 함수를 쓰기만 하면 됩니다. 만일, 어떤 데이터 멤버를 public으로 내놨다면 모두가 이 멤버에 대해 읽기 및 쓰기 접근권한을 가지게 되지만, 이 값을 읽고 쓰는 ..
항목 21 : 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자 유리수를 나타내는 클래스가 하나 있다고 가정합시다. 이 클래스에는 두 유리수를 곱하는 멤버 함수가 선언되어 있습니다. 1 2 3 4 5 6 7 8 9 10 11 12 class Rational { public : Rational(int numerator = 0, int denominator = 1); ... private : int n, d; friend const Rational operator*(const Rational& lhs, const Rational& rhs); }; Colored by Color Scripter 여기서 operator*를 보면 이 함수가 참조자를 반환하도록 만들어졌다면, 이 함수가 반환하는 참조..
항목 20 : '값에 의한 전달'보다는 '상수객체 참조자에 의한 전달' 방식을 택하는 편이 대개 낫다 기본적으로 C++는 함수로부터 객체를 전달받거나 함수에 객체를 전달할 때 '값에 의한 전달' 방식을 사용합니다. 특별히 다른 방식을 지정하지 않는 한, 함수 매개변수는 실제 인자의 '사본'을 통해 초기화되며, 어떤 함수를 호출한 쪽은 그 함수가 반환한 값의 '사본'을 돌려받습니다. 이들 사본을 만들어내는게 복사 생성자 입니다. 이 점 때문에 '값에 의한 전달'이 고비용의 연산이 되기도 합니다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Person { public : Person(); virtual ~Person(); ... private ..
항목 19 : 클래스 설계는 타입 설계와 똑같이 취급하자 여러분은 효과적인 클래스를 설계할 때 어떻게 하십니까? 여러분이 직면하게 될 고려사항이 무엇인지부터 파악하는 것이 우선이겠지요. 어떤 클래스를 설계하든 간에 사실상 모든 경우에 여러분의 후두부를 괴롭힐 질문들을 아래에 모아 보았습니다. 이들 질문의 대답에 따라 설계를 제한하는 것들이 생기게 되는데, 이 부분 역시 신경 쓰지 않으면 안됩니다. 새로 정의한 타입의 객체 생성 및 소멸은 어떻게 이루어져야 하는가? 이 부분이 어떻게 되느냐에 따라 클래스 생성자 및 소멸자의 설계가 바뀝니다. 그뿐 아니라 메모리 할당 함수(operator new, operator new[], operator delete, operator delete[] 입니다. 8장 참조)..
항목 18 : 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자 '제대로 쓰기에 쉽고 엉터리로 쓰기에 어려운' 인터페이스를 개발하려면 우선 사용자가 저지를 만한 실수의 종류를 머리에 넣어두고 있어야 합니다. 새로운 타입을 들여와 인터페이스를 강화하면 상당수의 사용자 실수를 막을 수 있습니다. 일단 적절한 타입만 제대로 준비되어 있으면, 각 타입의 값에 제약을 가하더라도 괜찮은 경우가 생기게 됩니다. 예를 들면 월이 가질 수 있는 유효한 값은 12개이므로, Month라는 타입은 이 사실을 제약으로 사용 할 수 있습니다. 예상되는 사용자 실수를 막는 다른 방법으로는 어떤 타입이 제약을 부여하여 그 타입을 통해 할 수 있는 일들을 묶어 버리는 방법이 있습니다. 제약 부여 방법으로 아주 흔히 ..