1부 소개

1장 들어가며

  1. 구상(개념)을 함수, 클래스, 열거형 등을 통해서 직접적으로 코드에 표현한다.

  2. 코드를 깔끔하고 효율적으로 만들겠다는 목표를 세운다.

  3. 과도한 추상화를 하지 않는다.

  4. 라이브러리로 표현될 가능성이 있는, 갈끔하고 효율적인 추상화를 제공하는 데 설계의 초점을 맞춘다.

  5. 매개변수화나 클래스 계층 구조 등을 통해 아이디어 사이의 관게를 직접적으로 코드에 표현한다.

  6. 독립적인 아이디어는 코드에 개별적으로 표현한다. 예를 들어 클래스 간의 상호 의존성은 피한다.

  7. C++는 객체지향적이지만은 않다.

  8. C++는 일반화 프로그래밍을 위한 것만은 아니다.

  9. 정적으로 체크할 수 있는 해결책을 우선 사용한다.

  10. 자원은 명시적으로 표시한다.

  11. 간단한 아이디어는 간단히 표현한다.

  12. 밑바닥에서부터 모든 것을 만들려고 애쓰지 말고 라이브러리, 그 중에서도 특히 표준 라이브러리를 활용한다.

  13. 타입이 풍부한 프로그래밍 스타일을 활용한다.

  14. 하위 수준의 코드가 반드시 효율적이지는 않다. 성능 문제 때문에 클래스, 템플릿, 표준, 라이브러리 구성 요소를 사용하는 걸 주저하지 않는다.

  15. 데이터가 불변속성을 갖고 있다면 캡슐화한다.

  16. C++는 단지 몇 가지 확장 기능을 가진 C가 아니다.



2장 C++ 둘러보기 : 기초

  1. 당황하지 말자! 시간이 지나면 알게 된다.
  2. 훌륭한 프로그램을 작성하기 위해 C++의 세부 사항까지 전부 알 필요는 없다.
  3. 언어 기능이 아니라 프로그래밍 기법에 집중하자.



3장 C++ 둘러보기 : 추상화 메커니즘

  1. 아이디어를 직접적으로 코드에 표현한다.
  2. 응용 개념을 직접적으로 코드에 표현해주는 클래스를 정의한다.
  3. 구체 클래스를 이용해서 간단한 개념과 성능이 중요한 구성 요소를 표현한다.
  4. '무방비'의 new와 delete 연산은 피한다.
  5. 자원 핸들과 RAII를 이용해서 자원을 관리한다.
  6. 인터페이스와 구현의 완벽한 분리가 필요할 때는 추상 클래스를 인터페이스로 활용한다.
  7. 클래스 계층 구조를 이용해서 내재적인 계층 구조를 가진 개념을 표현한다.
  8. 클래스 계층 구조를 설계할 때는 구현 상속과 인터페이스 상속을 구분한다.
  9. 객체의 복사, 이동, 소멸을 통제한다.
  10. 컨테이너는 값으로 반환한다(효율성이 중요하다면 move를 이용한다.)
  11. 강력한 자원 안전성을 제공한다. 즉 자원이라고 여겨지는 것이라면 절대로 누출시키지 않는다.
  12. 자원 핸들 템플릿으로 정의된 컨테이너를 이용해서 동일한 타입의 값으로 이뤄진 집합을 보관한다.
  13. 함수 템플릿을 이용해서 일반적인 알고리즘을 표현한다.
  14. 람다를 비롯한 함수 객체를 이용해서 정책과 작동을 표현한다.
  15. 타입 및 템플릿 별칭을 이용해서 유사한 타입이나 구현에 따라 변할 수 있는 타입에 대해 동일한 이름을 부여한다.


4장 C++ 둘러보기 : 컨테이너와 알고리즘

  1. 바퀴를 다시 만들 필요는 없다. 라이브러리를 활용한다.
  2. 선택 가능할 경우에는 다른 라이브러리보다 표준 라이브러리를 우선 사용한다.
  3. 표준 라이브러리가 만능이라고 생각하지는 말기 바란다.
  4. 사용하려는 기능에 대한 헤더를 #include 하는 것을 잊지 않는다.
  5. 표준 라이브러리 기능은 std 네임스페이스 범위로 정의된다는 점을 명심한다.
  6. C 스타일 문자열보다 string을 우선 사용한다.
  7. istream은 타입을 구분하고, 타입 안전성이 있으며, 확장성이 있다.
  8. T[] 보다 vector<T>, map<K, T>, unordered_map<K,T>를 우선 사용한다.
  9. 표준 커네이너와 그들의 장단점을 파악한다.
  10. vector를 기본 컨테이너로 활용한다.
  11. 가급적 간결한 데이터 구조를 사용한다.
  12. 의심스럽다면 범위 체크 벡터를 사용한다.
  13. push_back() 또는 back_inserter()를 사용해서 컨테이너에 원소를 추가한다.
  14. 배열에 realloc()을 사용하지 않고, vector에 push_back()을 사용한다.
  15. 일반적인 예외는 main()에서 잡는다.
  16. 표준 알고리즘을 파악해서 직접 만든 루프보다는 표준 알고리즘을 우선 사용한다.
  17. 반복자가 장황해지면 컨테이너 알고리즘을 정의한다.
  18. 완전한 컨테이너에 대해서는 범위기반 for 루프를 사용한다.



5장 C++ 둘러보기 : 병행성과 유틸리티

  1. 자원 핸들을 이용해서 자원을 관리한다(RAII)
  2. unique_ptr을 이용해서 다형성 타입의 객체를 참조한다.
  3. shared_ptr을 이용해서 공유 객체를 참조한다.
  4. 병행성에 대해서는 타입 안전적인 메커니즘을 사용한다.
  5. 공유 데이터의 사용은 최소화한다.
  6. 심사숙고나 실제적인 측정 없이 '효율성'이라는 이유 때문에 통신을 위해 공유 데이터를 선택하지 말기 바란다.
  7. 스레드보다는 병행 태스크의 관점에서 생각한다.
  8. 라이브러리는 규모가 크거나 복잡하지 않아도 쓸모가 있을 수 있다.
  9. 효율성에 대해서 주장하기 전에 자신의 프로그램을 측정해봐야 한다.
  10. 타입 속성에 명시적으로 의존하는 코드를 작성할 수 있다.
  11. 간단한 패턴 매칭을 위해서는 정규 표현식을 사용한다.
  12. 언어만 사용해서 본격적인 수치 계산을 처리하고 시도하지 않는다. 라이브러리를 활용한다.
  13. 수치 타입의 속성은 numeric_limits를 통해 접근할 수 있다.



2부 기본 기능

6장 타입과 선언

  1. 언어 정의 이슈에 대한 최종 결정 사항은 ISO C++ 표준을 참고한다.
  2. 지정되지 않거나 정의되지 않은 동작은 삼간다.
  3. 구현별 정의에 따르는 동작에 반드시 의존하는 코드는 격리한다.
  4. 문자의 수치 값에 대한 불필요한 추정은 삼간다.
  5. 0으로 시작하는 정수는 7진수라는 점을 명심한다.
  6. '마법의 상수'는 피한다.
  7. 정수의 크기에 대한 불필요한 추정은 삼간다.
  8. 부동소수점 타입의 범위와 정밀도에 대한 불필요한 추정은 삼간다.
  9. signed char나 unsigned char보다 일반적인 char가 낫다.
  10. 부호 있는 타입과 부호 없는 타입 간의 변환은 조심한다.
  11. 하나의 선언에서는 하나의 이름만 선언한다.
  12. 통상적인 이름과 지역 이름은 짧게 만들고, 자주 사용되지 않는 이름과 비지역 이름은 길게 만든다.
  13. 이름은 비슷하게 만들지 않는다.
  14. 타입보다는 의미에 맞춰 객체에 이름을 붙인다.
  15. 일관된 명명 규칙을 준수한다.
  16. ALL_CAPS 이름을 피한다.
  17. 유효 범위는 가급적 좁게 만든다.
  18. 하나의 유효 범위 내에서뿐만 아니라 이를 둘러싼 바깥 유효 범위 내에서도 같은 이름은 쓰지 않는다.
  19. 이름이 있는 타입을 가진 선언에 대해서는 {} 초기화 식 문법을 사용하는 것이 좋다.
  20. auto를 사용하는 선언에서는 초기화에 = 문법을 사용하는 것이 좋다.
  21. 초기화되지 않은 변수는 삼간다.
  22. 기본 제공 타입이 변경될 수 있는 값을 표시하는 데 사용된 경우에는 기본 제공 타입에 의미 있는 이름을 붙이기 위해 별칭을 사용한다.
  23. 별칭은 다른 타입을 다른 이름으로 표시하고 싶을 때 사용한다. 새로운 타입을 정의하고 싶다면 열거형과 클래스를 이용한다.



7장 포인터, 배열, 참조

  1. 포인터는 간결하고 직관적으로 사용한다.
  2. 허용되지 않은 포인터 연산은 삼간다.
  3. 경계 배열 너머에 쓰지 않도록 조심한다.
  4. 다차원 배열을 피한다. 대신 적절한 컨테이너를 정의한다.
  5. 0이나 NULL 보다 nullptr을 이용한다.
  6. 기본 제공 C스타일의 배열보다 컨테이너(vector, array, valarray 등)를 이용한다.
  7. 0으로 종료되는 char의 배열보다 string을 이용한다.
  8. 백슬래시를 복잡하게 사용하는 문자열 리터럴에는 원시 문자열을 이용한다.
  9. 보통의 참조자 인자보다 const 참조자 인자를 선택한다.
  10. 포워딩과 이동 의미 구조에만 우변 값 참조자를 이용한다.
  11. 소유권을 표시하는 포인터는 핸들 클래스 내부에 둔다.
  12. 저수준의 코드를 제외하고는 void*를 삼간다.
  13. 인터페이스에서 불변성을 표헌하기 위해 const 포인터와 const 참조자를 이용한다.
  14. '객체 없음'이 타당한 선택인 경우를 제외하고는 포인터보다는 참조자를 인자로 선택한다.


8장 구조체, 공용체, 열거형

  1. 데이터 용량의 최소화가 필요한 경우에는 작은 멤버보다 좀 더 큰 멤버를 앞에두는 구조로 만든다.
  2. 하드웨어에 노출되는 데이터 구조를 표시하려면 비트필드를 활용한다.
  3. 여러 개의 값을 하나의 바이트에 구겨 넣는 단순한 방식으로 메모리 소비를 최적화하려고 시도하지 말기 바란다.
  4. union은 메모리 공간 절약에 활용하고 타입 변환에는 이용하지 않는다.
  5. 열거형을 이용해서 이름 있는 상수 집합을 표시한다.
  6. 예기치 않은 결과를 최소화하기 위해 '일반' enum보다 enum class 를 사용한다.
  7. 안전하고 간편한 활용을 위해 열거형에 대해 연산을 정의한다.


9장 문장

  1. 초기화할 수 있는 값이 생기기 전에는 변수 선언을 삼간다.
  2. 가능하다면 if문보다 switch문을 사용한다.
  3. 가능하다면 for문보다 범위 기반 for문을 사용한다.
  4. 명확한 루프 변수가 있는 경우에는 while문보다 for문을 사용한다.
  5. 명확한 루프 변수가 없는 경우에는 for문보다 while문을 사용한다.
  6. do문은 피한다.
  7. goto문은 피한다.
  8. 주석은 간결하게 유지한다.
  9. 코드를 보면 명확히 알 수 있는 사항은 주석에 적지 않는다.
  10. 주석에 의도를 설명한다.
  11. 일관된 들여쓰기 스타일을 유지한다.



10장 표현식

  1. 다른 라이브러리나 '직접 짠 코드'보다 표준 라이브러리를 사용한다.
  2. 문자 수준의 입력은 어쩔 수 없을 때만 사용한다.
  3. 읽기를 수행할 때는 언제나 형식이 맞지 않는 입력을 고려한다.
  4. 언어 기능을 직접적으로 이용하기보다는 적합한 추상화를 우선 사용한다.
  5. 복잡한 표현식을 피한다.
  6. 연산자 우선순위에 대해 의심이 생긴다면 괄호를 친다.
  7. 정의되지 않은 평가 순서를 가진 표현식은 피한다.
  8. 축소 변환은 피한다.
  9. '매직 상수'를 피하기 위해 기호 상수를 정의한다.


11장 선택 연산

  1. 접미사 ++보다 접두사 ++를 우선 사용한다.
  2. 자원 핸들을 이용해서 누출, 때 이른 소멸, 이중 소멸을 피한다.
  3. 꼭 그럴 필요가 없다면 객체를 자유 저장 공간에 넣지 않는다. 유효 범위를 가진 변수를 우선 사용한다.
  4. '무방비의 new'나 '무방비의 delete'는 피한다.
  5. RAII를 사용한다.
  6. 연산이 주석을 필요로 하는 경우라면 람다보다 이름을 가진 함수 객체를 우선 사용한다.
  7. 연산이 범용적으로 유용하다면 람다보다 이름을 가진 함수 객체를 우선 사용한다.
  8. 람다는 짧게 만든다.
  9. 유지 보수성과 정확성을 위해 참조자에 의한 캡처에 대해서는 신중을 기한다.
  10. 컴파일러가 람다의 반환 타입을 추론하게 만든다.
  11. 생성에는 T{e} 표기법을 사용한다.
  12. 명시적 타입 변환(캐스트)는 피한다.
  13. 명시적 타입 변환이 필요한 경우에는 이름 있는 캐스트를 우선 사용한다.
  14. 수치 타입간의 변환에는 narrow_cast<>()같은 런타임 체크 캐스트의 사용을 고려한다.


12장 함수

  1. 의미 있는 연산은 신중하게 이름을 붙인 함수로 '패키지'화한다.
  2. 함수는 단일한 논리 연산을 수행해야 한다.
  3. 함수는 짧게 만든다.
  4. 지역 변수를 가리키는 포인터나 지역 변수에 대한 참조자는 반환하지 않는다.
  5. 어떤 함수가 컴파일 타임에 평가되어야 한다면 constexpr로 선언한다.
  6. 어떤 함수가 반환할 수 없다면 [[noreturn]]으로 표시한다.
  7. 작은 객체에 대해서는 값에 의한 전달을 사용한다.
  8. 변경할 필요가 없는 큰 값을 전달할 때는 const 참조자에 의한 전달을 사용한다.
  9. 인자를 통해 객체를 변경하기보다는 return 값으로서 결과를 반환한다.
  10. 이동과 전달을 구현하려면 우변 값 참조자를 사용한다.
  11. '객체 없음'이 유효한 대안인 경우에는 포인터를 전달한다.
  12. 그럴 필요가 있을 때만 const가 아닌 참조자에 의한 전달을 사용한다.
  13. const를 광범위하고 일관성 있게 사용한다.
  14. char*나 const char* 인자는 C스타일 문자열을 가리킨다고 가정한다.
  15. 배열을 포인터로 전달하는 것은 피한다.
  16. 길이를 모르는 균일한 리스트는 initializer_list<T>로 전달한다.
  17. 지정되지 않은 인자의 개수(...)는 피한다.
  18. 함수가 서로 다른 타입에 개념적으로 동일한 작업을 수행할 때는 오버로딩을 활용한다.
  19. 정수에 대해 오버로딩을 할 경우에는 일반적인 모호성을 제거해 주는 함수를 제공한다.
  20. 함수에 대해 선행 조건과 후행 조건을 지정한다.
  21. 함수를 가리키는 포인터보다 함수 객체와 가상 함수를 우선적으로 사용한다.
  22. 매크로는 피한다.
  23. 매크로를 사용해야 한돠면 대문자를  많이 가진 이상해 보이는 이름을 사용한다.


13장 예외 처리

  1. 설계 초기에 오류 처리 전략을 개발한다.
  2. 주어진 작업을 수행할 수 없다는 점을 나타내려면 예외를 던진다.
  3. 오류 처리에 예외를 이용한다.
  4. 예외로는 목적을 가지고 설계한 사용자 정의 타입을 사용한다.
  5. 어떤 이유에서 예외를 사용할 수 없다면 그것을 흉내 낸다.
  6. 계층적인 오류 처리를 사용한다.
  7. 오류 처리의 개별적인 부분들은 간단하게 만든다.
  8. 모든 함수에서 모든 예외를 잡으려고 시도하지 않는다.
  9. 기본적인 보장은 항상 제공한다.
  10. 그러지 않을 이유가 없다면 강력한 보장을 제공한다. 
  11. 생성자 내에서 획득한 모든 자원은 해당 생성자에서 예외를 던지기 전에 반드시 해제한다.
  12. 좀 더 지역적인 제어로 충분한 경우에는 예외를 사용하지 않는ㄴ다.
  13. '자원 획득은 초기화' 기법을 이용해서 자원을 관리한다.
  14. try 블록의 사용은 최소화한다.
  15. 모든 프로그램이 예외 안전적일 필요는 없다.
  16. 'RAII'와 예외 핸들러를 이용해서 불변속성을 관리한다.
  17. 덜 구조화된 finally보다는 적합한 자원 핸들을 우선 사용한다.
  18. 불변속성을 기반으로 오류 처리 전략을 설계한다.
  19. 컴파일 타임에 체크될 수 있는 것이라면 대개는 컴파일 타임에 체크하는 것이 최선이다.
  20. 다양한 수준의 체크/강제를 수용할 수 있게 오류 처리 전략을 설계한다.
  21. 함수가 예외를 던질 수 없다면 noexcept로 선언한다.
  22. 예외 지정은 사용하지 않는다.
  23. 계층 구조의 일부분이 될 수 있는 예외는 참조자로 잡는다.
  24. 모든 예외가 exception 클래스에서 파생된다고 가정하지 않는다.
  25. main()이 모든 예외를 붙잡고 보고하게 만든다.
  26. 대체할 것이 준비되기 전에 정보를 소멸시키지 않는다.
  27. 대입문에서 에외를 던지기 전에 피연산자는 유효한 상태여야 한다.
  28. 소멸자에서는 예외를 절대로 던지지 않는다.
  29. 통상적인 코드와 오류 처리 코드는 분리한다.
  30. new에 의해 할당된 다음 예외가 일어난 경우에 해제되지 않는 메모리로 인해서 발생하는 메모리 누출에 주의한다.
  31. 함수에 의해 던져질 수 있는 모든 예외는 던져질 것이라고 가정한다.
  32. 라으버리는 일방적으로 프로그램을 종료하지 말아야 한다. 대신 예외를 던지고 호출자가 결정하게 한다.
  33. 라이브러리는 최종 사용자를 대상으로 한 진단적 출력을 내보내지 말아야 한다. 대신 예외를 던지고 호출자가 결정하게 한다.



14장 네임스페이스

  1. 네임스페이스를 이용해서 논리적 구조를 표현한다.
  2. main()을 제외한 비지역적 이름은 모두 어떤 네임스페이스에 넣는다.
  3. 무관한 네임스페이스에 불필요하게 접근을 하지 않고도 편리하게 이용할 수 있도록 네임스페이스를 설계한다.
  4. 매우 짧은 이름은 네임스페이스에 쓰지 않는다.
  5. 필요하다면 긴 네임스페이스 이름을 줄이기 위해 네임스페이스 별칭을 사용한다.
  6. 네임스페이스 사용자에게 심각한 표기적 부담을 지우지 않도록 한다. 
  7. 인터페이스와 구현에 대해서는 별개의 네임스페이스를 사용한다.
  8. 네임스페이스 멤버를 정의할 때는 Namespace::member 표기를 사용한다.
  9. inline 네임스페이스를 이용해서 버전 관리를 지원한다.
  10. using 지시자는 전환, 기반 라이브러리(std등)으로 사용하거나 지역 유효 범위 내에서 사용한다.
  11. 헤더 파일에 using 지시자를 넣지 않는다.



15장 소스 파일과 프로그램

  1. 헤더 파일을 이용해서 인터페이스를 표시하고 논리적 구조를 강조한다.
  2. 그것의 함수를 구현하는 소스 파일 안에 헤더를 #include 한다.
  3. 서로 다른 해석 단윙에서 같은 이름을 갖거나 비슷하지만 다른 뜻을 가진 전역 객체를 정의하지 않는다.
  4. 헤더 안에서 인라인이 아닌 함수는 피한다.
  5. 전역 유효 범위와 네임스페이스 안에서만 #include를 사용한다.
  6. 완전한 선언만을 #include 한다.
  7. 인클루드 가드를 사용한다.
  8. 전역 이름을 피하기 위해 네임스페이스 안에 C헤더를 #include 한다.
  9. 헤더는 자기 완결적으로 만든다.
  10. 사용자 인터페이스와 구현자 인터페이슬르 구분한다.
  11. 평균적인 사용자의 인터페이스와 전문 사용자의 인터페이스를 구분한다.
  12. C++로 작성되지 않은 프로그램의 일부로 사용될 예정인 코드에서 런타임 초기화를 요구하는 비지역 객체는 피한다.


3부 추상화 메커니즘

16장 클래스

  1. 클래스로 개념을 표현한다.
  2. 클래스의 인터페이스는 구현과 분리한다.
  3. 정말로 데이터뿐이고 데이터 멤버에 대해 의미 있는 불변속성이 없는 경우에만 공개 데이터를 사용한다.
  4. 객체의 초기화를 처리하기 위해 생성자를 정의한다.
  5. 기본적으로 단일 인자 생성자는 explicit으로 선언한다.
  6. 자신의 객체를 변경하지 않는 멤버 함수는 const로 선언한다.
  7. 구체 타입은 가장 간단한 종류의 클래스다. 적용 가능한 경우에는 좀 더 복잡한 클래스나 순수한 데이터 구조보다 구체 타입을 우선 사용한다.
  8. 클래스의 표현에 직접적인 접근을 필요로 하는 경우에만 함수를 멤버로 만든다.
  9. 네임스페이스를 이용해서 클래스와 그것의 보조 함수의 연관관계를 명시적으로 만든다.
  10. 클래스 내부 초기화 식을 이용해서 생성자의 중복을 피한다.
  11. 클래스의 표현에 접근해야 하지만 구체적인 객체에 대해 호출될 필요가 없는 함수는 static 멤버 함수로 만든다.



17장 생성, 마무리, 복사와 이동

  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. 클래스에 새로운 멤버를 추가할 때는 해당 멤버를 초기화하기 위해 갱신되어야 하는 사용자 정의 생성자가 있는지 확인한다.



18장 연산자 오버로딩

  1. 주로 관용적인 사용법을 흉내 낼 목적으로 연산자를 정의한다.생성자가 자원을
  2. 기본 복사가 어떤 타입에 적합하지 않다면 복사를 재정의하든지 금지한다.
  3. 큰 피연산자에 대해서는 const 참조자 인자 타입을 사용한다.
  4. 큰 결과에 대해서는 이동 생성자를 이용한다.
  5. 표현에 접근해야 하는 연산에 대해서는 비멤버보다 멤버 함수를 우선 사용한다.
  6. 표현에 접근해야 할 필요가 없는 연산에 대해서는 멤버 함수보다 비멤버 함수를 우선 사용한다.
  7. 네임스페이스를 이용해서 클래스와 보조 함수를 연결한다.
  8. 대칭적인 연산자에 대해서는 비멤버 함수를 사용한다.
  9. 좌변 값과 왼쪽 피연산자를 필요로 하는 연산자를 표현하기 위해서는 멤버 함수를 사용한다.
  10. 관용적인 표기법을 흉내 내려면 사용자 정의 리터럴을 사용한다.
  11. 클래스의 기본 의미 구조가 요구하는 경우에만 데이터 멤버에 대한 Set과 Get()함수를 제공한다.
  12. 암시적 변환의 도입은 신중히 해야한다.
  13. 값을 소멸시키는 변환은 피한다.
  14. 생성자와 변환 연산자 양쪽 모두와 동일한 변환은 정의하지 않는다.


19장 특수 연산자

  1. operator[]()는 첨자 연산과 단일 값 기반의 선택에 사용한다.
  2. operator()()는 호출 의미 구조, 첨자 연산, 다중 값 기반의 선택에 사용한다.
  3. operator->()는 '스마트 포인터'를 역참조하는 데 사용한다.
  4. 가급적 후위형 ++보다 전위형 ++를 사용한다. (전위형은 참조를 반환, 후위형은 새 객체 반환)
  5. 정말로 그래야 하는 경우에만 전역 operator new()와 operator delete()를 정의한다.
  6. 멤버 operator new()와 멤버 operator delete()를 정의해서 특정 클래스 또는 클래스의 계층 구조 객체에 대한 할당 및 할당 해제를 제어한다.
  7. 사용자 정의 리터럴을 사용해서 관용적인 표기법을 흉내 낸다.
  8. 선택적인 사용을 허용하려면 리터럴 연산자를 별도의 네임스페이스에 넣는다.
  9. 특수하지 않은 용도에 대해서는 직접 연습한 결과물보다 표준 string을 사용하기 바란다.
  10. 클래스 표현에 접근해야 하는 비멤버 함수가 필요하다면 프렌드 함수를 이용한다.
  11. 클래스의 표현에 대한 접근을 허용하는 데는 가급적 프렌드 함수보다는 멤버 함수를 이용하기 바란다.


20장 파생 클래스

  1. 타입 필드는 피한다.
  2. 다형적 객체는 포인터와 참조자를 통해 접근한다.
  3. 추상 클래스를 이용해서 깔끔한 인터페이스의 제공에 설계의 초점을 맞춘다.
  4. override를 이용해서 대규모 클래스 계층 구조에서 재정의를 명시적으로 만든다.
  5. final은 절제해서 사용한다.
  6. 추상 클래스를 이용해서 인터페이스를 지정한다.
  7. 추상 클래스를 이용해서 구현 세부 사항을 인터페이스와 분리한다.
  8. 가상 함수를 가진 클래스는 가상 소멸자를 가져야 한다.
  9. 추상 클래스는 대개 생성자를 필요로 하지 않는다.
  10. 구현 세부 사항에 대해서는 가급적 private 멤버를 사용한다.
  11. 인터페이스에 대해서는 가급적 public 멤버를 사용한다.
  12. protected 멤버는 정말 필요할 때만 조심해서 사용한다.
  13. 데이터 멤버는 protected로 선언하지 않는다.

 

21장 클래스 계층 구조

  1. new를 이용해서 생성된 객체의 delete를 잊지 않기 위해서는 unique_ptr이나 shared_ptr을 이용한다.
  2. 인터페이스로 사용할 기반 클래스에는 데이터 멤버를 넣지 않는다.
  3. 추상 클래스를 이용해서 인터페이스를 표현한다.
  4. 추상 클래스에는 가상 소멸자를 제공해서 올바른 마무리를 보장한다.
  5. 대규모 클래스 계층 구조에서는 override를 사용해서 재정의를 명시적으로 만든다.
  6. 추상 클래스를 사용해서 인터페이스 상속을 지원한다.
  7. 데이터 멤버를 가진 기반 클래스를 이용해서 구현 상속을 지원한다.
  8. 통상적인 다중 상속을 이용해서 기능의 합집합을 표현한다.
  9. 다중 상속을 이용해서 인터페이스에서 구현을 분리한다.
  10. 가상 기반 클래스를 이용해서 계층 구조 내에서 일부 클래스에 공통된 뭔가를 표현한다.