[More Effective C++] ch01. 기본 개념들
항목1. 포인터와 참조자를 구분하자
포인터
- 객체가 존재하지 않아도 쓸 수 있음
- 다른 객체를 가리킬 수 있다. ( 가리키는 객체의 주소값이 바뀌는것임)
- 딱히 가리킬 객체의 주소가 없을 때 or 하나의 변수를 가지고 여러개의 객체를 바꾸어 참조해야 할 때 사용
참조자
- 메모리 공간을 차지한 객체를 참조(NULL 참조 불가능)
- 초기화 필수
string s("goldory");
string& rs = s;
- 포인터보다 좋은 점은 유효성 검사를 하지 않는다. (포인터는 널포인터인지 검사함)
- 초기화될 때 참조했던 객체만 참조 가능
=> 문자열 s1을 참조하도록 초기화한 변수 a에 문자열 s2로 다시 초기화 한다면 a가 가리키는 위치는 s1이지만, s1의 값은 s2로 바뀐다.
- 참조할 포인터가 처음부터 끝까지 존재할 것임을 알고있을 때
or 참조하는 대상 객체를 바꿀 필요가 없을 때
or 연산자 함수를 구현할 때 사용
항목2. 가능한 C++ 스타일의 캐스트를 즐겨 쓰자
C 스타일의 캐스트는 아무 조건 없이 타입을 바꿈
-> C++ 캐스트 연산자 4가지 도입
-> C++ 에서의 타입 캐스팅 형태 : static_cast<타입> (표현식)
int a, b;
//C style
double res=((double) a)/b;
//C++ style
double res=static_cast<double>(a)/b;
1. static_cast : C 캐스트랑 똑같은 의미와 형변환 능력
2. const_cast : 표현식의 상수성이나 휘발성을 없애는 용도
3. dynamic_cast : 기본 클래스의 객체에 대한 포인터나 참조자의 타입을 파생 혹은 형제 클래스의 타입으로 변환함.
but!! 상속 계층 구조를 오갈 때만 사용가능, 가상함수가 있어야함 (책에선 update()), 상수성 제거 불가능
4. reinterpret_cast : 함수 포인터 타입을 서로 바꾸는 것. ***
항목3. 배열과 다형성은 같은 수준으로 놓고 볼 것이 아니다.
객체 포인터는 객체의 주소 값을 저장할 수 있는 포인터이다.
따라서 Parent 클래스와 이를 상속하는 Child 클래스가 있다면,
Parent 클래스의 포인터는 Parent 객체의 주소 뿐만 아니라 Child 클래스의 객체의 주소값도 저장이 가능하다.
Parent 클래스의 참조자는 Parent 객체 뿐만 아니라 Child 클래스의 객체도 참조 가능하다.
파생클래스는 보통 기본 클래스보다 더 많은 데이터를 가지고 있기 때문에 그 크기도 기본 클래스보다 크다. 따라서 기본 클래스 포인터를 통해 파생 클래스 객체의 배열에 접근하는 것은 위험하다.
->다형성과 포인터 산술연산은 간단히 생각해서는 안된다.
항목4. 쓸데 없는 기본 생성자는 그냥 두지 말자
기본생성자 없을 때>>
1. 배열이 힙에 있지 않다면, 배열의 요소를 정의된 위치에서 생성자 매개변수를 직접 넣어준다.
2. 객체의 배열 대신에 포인터의 배열을 사용 (자원낭비, 메모리 사용량 커짐)
기본생성자 있을 때>
1. 클래스 생성자가 객체의 멤버 데이터를 확실하게 초기화해야함 -> but 어려움