아이템 3 : private 생성자나 열거 타입으로 싱글턴임을 보증하라 싱글턴이란 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말한다. 클래스를 싱글턴으로 만들면 이를 사용하는 클라이언트를 테스트하기가 어려워질 수 있다. 싱글턴을 만드는 방식은 보통 둘 중 하나다. 두 방식 모두 생성자는 private으로 감춰두고, 유일한 인스턴스에 접근할 수 있는 수단으로 public static 멤버를 하나 마련해둔다. 우선 public static 멤버가 final 필드인 방식을 살펴보자. 1 2 3 4 5 6 public class Elvis{ public static final Elvis INSTANCE = new Elvis(); private Elvis() { ... } public void leaveTh..
아이템 2 : 생성자에 매개변수가 많다면 빌더를 고려하라 정적 팩터리와 생성자에는 똑같은 제약이 하나 있다. 선택적 매개변수가 많을 때 적절히 대응하기 어렵다는 점이다. 이런 클래스용 생성자 혹은 정적 팩터리는 어떤 모습일까? 프로그래머들은 이럴 때 점층적 생성자 패턴을 즐겨 사용했다. 필수 매개변수만 받는 생성자, 필수 매개변수와 선택 매개변수 1개를 받는 생성자, ... 형태로 선택 매개변수를 전부 다 받는 생성자까지 늘려가는 방식이다. 매개변수가 많더라도 점층적 생성자 패턴도 쓸 수는 있지만, 매개변수 개수가 많아지면 클라이언트 코드를 작성하거나 읽기가 어려워진다. 선택 매개변수가 많을 때 활용할 수 있는 다른 대안이 있다. 바로 자바빈즈 패턴이다. 매개변수가 없는 생성자로 객체를 만든 후, 세터 ..
아이템 1 : 생성자 대신 정적 팩터리 메서드를 고려하라 클래스는 클라이언트에 public 생성자 대신(혹은 생성자와 함께) 정적 팩터리 메서드를 제공할 수 있다. 이 방식에는 장점과 단점이 모두 존재한다. 먼저 좋은 장점 다섯 가지를 알아보자. 이름을 가질 수 있다. 호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다. 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다. 이러한 장점들을 가지고 있다. 하지만 몇가지의 단점도 존재한다. 상속을 하려면 public이나 protected 생성자가 필요하니 정적 팩터리 메서드만 제공하면 하위 클래스를..
항목 43 : 템플릿으로 만들어진 기본 클래스 안의 이름에 접근하는 방법을 알아 두자 1 2 3 4 5 6 template class MsgSender{ public : ... void sendSecret(const MsgInfo& info){...} }; Colored by Color Scripter 괄호 안에 아무것도 없는 template의 뜻은 "이건 템플릿도 아니고 클래스도 아니다"라는 것입니다. 위의 코드는 MsgSender 템플릿을 템플릿 매개변수가 CompanyZ일 때 쓸 수 있도록 특수화한 버전입니다. 이러한 특수화는 완전 템플릿 특수화라고 합니다. MsgSender 템플릿이 CompanyZ 타입에 대해 특수화되었고, 이때 이 템플릿의 매개변수들이 하나도 빠짐없이 구체적인 타입으로 정해진 ..
항목 42 : typename의 두 가지 의미를 제대로 파악하자 1 2 3 4 5 6 7 8 9 10 11 12 template void print2nd(const C& container) { if(container.size() >= 2) { C::const_iterator iter(container.begin()); ++iter; int value = *iter; std::cout = 2) { typename C::const_iterator iter(container.begin()); ... } } Colored by Color Scripter 어느 때이든지 템플릿 안에서 중첩 의존 이름을 참조할 경우에는, 그 이름 앞에 typename 키워드를 붙여 주는 것을 잊지 마세요. "typename은 중첩 ..
항목 40 : 다중 상속은 심사숙고해서 사용하자 다중 상속(multiple inheritance: MI)에 대해 꼭 기억하고 있어야 할 점중 하나는, 둘 이상의 기본 클래스로부터 똑같은 이름(함수, typedf 등)을 물려받을 가능성이 생겨 버린다는 점입니다. 다중 상속 때문에 모호성이 생긴다는 것이죠. 아래의 예시를 보시죠. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class BorrowableItem { // 라이브러리로부터 여러분이 가져올 수 있는 어떤 것 public : void checkOut(); // 라이브러리로부터 체크아웃합니다. ... }; class ElectronicGadget { private: bool checkOut() const; // 자체 테..
항목 39 : private 상속은 심사숙고해서 구사하자 private 상속의 의미는 is-implemented-in-terms-of입니다. private 상속은 소프트웨어 설계 도중에는 아무런 의미도 갖지 않으며, 단지 소프트웨어 구현 중에만 의미를 가질 뿐입니다. private를 언제 사용해야 할지에 대한 궁금증을 가질 수 있습니다. 그에 대한 답변은 간단합니다. 할 수 있으면 객체 합성을 사용하고, 꼭 해야 하면 private 상속을 사용하십시오. 꼭 해야 하는 경우는 주로 "비공개 멤버를 접근할 때 혹은 가상 함수를 재정의할 경우" 입니다. private 상속 대신에 public 상속에 객체 합성 조합이 더 자주 즐겨 쓰입니다. 두 가지의 좋은 점이 있기 때문입니다. 첫째, 클래스를 설계하는데 있..
항목 38 : "has-a(...는...를 가짐)" 혹은 "is-implemented-in-terms-of(...는...를 써서 구현됨)"를 모형화할 때는 객체 합성을 사용하자 합성이란, 어떤 타입의 객체들이 그와 다른 타입의 객체들을 포함하고 있을 경우에 성립하는 그 타입들 사이의 관계를 일컫습니다. 포함된 객체들을 모아서 이들을 포함한 다른 객체를 합성한다는 뜻입니다. public 상속의 의미가 "is-a(...는 ...의 일종이다)"라고 공부했었습니다. 객체 합성 역시 의미를 갖고 있습니다. 두 가지의 뜻을 가지고 있는데, "has-a(...는 ...를 가짐)"을 뜻할수도 있고 "is-implemented-in-terms-of(...는 ...를 써서 구현됨)"을 뜻할수도 있습니다. 이렇게 뜻이 두 ..
항목 37 : 어떤 함수에 대해서도 상속받은 기본 매개변수 값은 절대로 재정의하지 말자 C++에서 상속받을 수 있는 함수의 종류는 가상 함수와 비가상 함수 두 가지 입니다. 이들 중 비가상 함수는 언제라도 재정의해서는 안 되는 함수입니다. 객체의 정적 타입은 프로그램 소스 안에 여러분이 놓는 선언문을 통해 그 객체가 갖는 타입입니다. 객체의 동적 타입은 현재 그 객체가 진짜로 무엇이냐에 따라 결정되는 타입입니다. 다시 말해, '이 객체가 어떻게 동작할 것이냐'를 가리키는 타입이 동적 타입이라 하겠습니다. 동적 타입은 프로그램이 실행되는 도중에 바뀔 수 있습니다. 대개 대입문을 통해 바뀌죠. 가상 함수는 동적으로 바인딩됩니다. (가상 함수의) 호출이 일어난 객체의 동적 타입에 따라 어떤 (가상) 함수가 호..