Chapter 1. C++ 에 왔으면 C++의 법을 따릅니다.
항목 1. C++를 언어들의 연합체로 바라보는 안목은 필수
- 절차적(procedual) : C언어가 기본
- 객체 지향(object oriented) : 클래스, 캡슐화, 상속, 다형성, 가상함수 등 개념 사용
- 일반화(generic), 템플릿 메타프로그래밍
- STL, 템플릿 라이브러리
항목 2. #define을 쓰려거든 const, enum, inline을 떠올리자
가급적 선행 처리자보다 컴파일러를 더 가까이 하자
매크로 대신 상수를 사용하자
1 2
| #define ASPECT_RATIO 1.653 const double AspetRatio = 1.653;
|
선행 처리자로 선언된 기호식 이름은 컴파일러 기호 테이블에 들어가지 않기 때문에 에러 발생 시 헷갈릴 수 있다.
주의점
상수 포인터를 정의하는 경우
const char * const authorName = "Scott Meyers";
클래스 멤버로 상수를 정의하는 경우 (컴파일러에서 상수 멤부 변수의 정의를 금지하는 경우)
상수의 정의을 구현 파일에 둔다.
1 2 3 4 5 6 7 8
| class CostEstimate { private: static const double FudgeFactor; ... };
const double CostEstimate::FudgeFactor = 1.35;
|
나열자 둔갑술(enum hack)
1 2 3 4 5 6
| class GamePlayer { private: enum { NumTurns = 5};
int scores[NumTurns]; };
|
매크로 함수보다 인라인 함수를 우선 생각하자
인라인 함수에 대한 템플릿을 준비하자
1 2 3 4 5
| template<typename T> inline void callWithMax(const T& a, const T& b) { f(a > b ? a : b); }
|
항목 3. 낌새만 보이면 const를 들이대 보자!
정의
상수 멤버 함수 : 해당 멤버 함수가 상수 객체에 대해 호출된 함수
1. 클래스의 인터페이스를 이해하기 좋게 한다.
2. 상수 객체를 사용할 수 있게 한다
비트수준상수성
멤버 함수가 그 객체의 어떤 데이터 멤버도 건드리지 않아야 한다.
논리적 상수성
상수 멤버 함수라고 해서 객체의 한 비트도 수정할 수 없는 것이 아니라 일부 몇 비트는 정도는 바꿀 수 있되 그것을 사용자측에서 알아채지 못하게만 하면 상수 멤버 자격이 있다.
mutable
사용 : 비정적 데이터 멤버를 상수 멤버 함수 안에서도 수정 할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12
| class CTextBlock{ ... mutable std::size_t textlength; ... };
std::size_t CTextBlock::length() const { ... textLength = std::strlen(pText); ... }
|
상수 멤버 및 비상수 멤버 함수에서 코드 중복 현상을 피하는 방법
- 기능적으로 서로 똑같게 구현되어 있을 경우 비상수 버전이 상수 버전을 호출하도록
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class TextBlock { public: ... const char& operator[](std::size_t position) const { ... return text[position]; }
char& operator[](std::size_t position) { return const_cast<char&>( static_const<const TextBlock&>(*this)[position]);_ } };
|
- 앞의 방법을 뒤집어(상수 버전이 비상수 버전을 호출 하는 것) 하지 않는 이유는 상수 함수는 객체의 상태를 바꾸지 않겠다고 컴파일러와 약속한 함수이기 떄문에 배신하는 셈이 됩니다.
항목 4. 객체를 사용하기 전에 반드시 그 객체를 초기화 하자
기본제공 타입의 객체는 직접 손으로 초기화합니다.
1 2
| int x = 0; const char * text = "A C-style string";
|
생성자에서 멤버 초기화 리스트를 사용하여 초기화 하고 리스트에 데이터 멤버를 나열할 떄는 클래스에 각 데이터 멤버가 선언된 순서와 똑같이 나열하자( 리스트 순서가 아닌 선언 순서로 초기화 되기 떄문에)
1 2 3 4 5 6 7 8 9 10 11
| class ABC{ ABC(int x, std::string str); private: int number; std::string name; };
ABC::ABC(int x, std::string str) : number(x), name(str) {}
|
비정역 정적 객체들의 초기화 순서는 보장되지 않는다. 해결책으로 비지역 정적 객체를 지역 정적 객체로 바꾼다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class FileSystem {...};
FileSystem& tfs() { static FileSystem fs; return fs; }
class Directory {...};
Directory::Directory( params ) { ... std::size_t disks = tfs().numDisks(); ... }
Directory& tempDir() { static Directory td; return td; }
|