일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- c++
- 게임
- 참조자
- 비교 함수 객체
- 오블완
- 스마트 포인터
- lua
- implicit conversion
- more effective c++
- 메타테이블
- 언리얼
- resource management class
- virtual function
- 루아
- 티스토리챌린지
- Vector
- 다형성
- exception
- 반복자
- Effective c++
- 암시적 변환
- reference
- 예외
- 상속
- UE4
- operator new
- Smart Pointer
- effective stl
- 영화 리뷰
- 영화
Archives
- Today
- Total
스토리텔링 개발자
[More Effective C++] 3. 다형성 객체의 배열 지양하기 본문
728x90
항목 3 : 배열과 다형성은 같은 수준으로 놓고 볼 것이 아니다.
상속성이 주는 혜택
- 기본 클래스 객체의 포인터나 참조자를 통해 파생 클래스 객체를 조작할 수 있다.
- 즉, 다형성을 가지고 있다.
- 파생 클래스 객체의 배열을 기본 클래스 포인터나 참조자를 통해 조작할 수 있다.
- 하지만, 이게 정말 바랬던 일일까..?
기본 클래스 배열 대신 파생 클래스 배열을 사용하는 경우
class BST { ... };
class BalancedBST : public BST { ... };
void printBSTArray(ostream& s, const BST array[], int numElements)
{
for(int i = 0 ; i < numElements ; ++i)
{
s << array[i];
}
}
BST BSTArray[10];
printBSTArray(cout, BSTArray, 10); // 잘 동작한다.
BalancedBST bBSTArray[10];
printBSTArray(cout, bBSTArray, 10); // 컴파일 에러는 나지 않는다. 허나...?
- 두 번째 printBSTArray는 미정의 결과이다.
배열과 포인터
- array[i] 는 실은 *(array + i)의 다른 표현일 뿐이다.
- 즉 array[i] 를 계산할 때는 i * sizeof(BST) 의 형태로 거리를 가늠하게 된다.
- printBSTArray에 파생 클래스 배열을 넘겼을 때
- i * sizeof(BalancedBST) 로 배열 거리를 가늠해야 하지만...
- 실제로는 i * sizeof(BST) 로 배열 거리를 가늠하게 된다!!
- 파생 클래스는 보통 기본 클래스보다 더 많은 데이터를 가지고 있으므로 당연히 크기도 기본 클래스보다 크기 마련이다.
- 그러므로 미정의 결과가 도출된다.
기본 클래스 배열 대신 파생 클래스 배열을 사용하는 또 다른 경우
void deleteArray(ostream& logStream, BST array[]) // 기본 클래스 배열을 받는 메소드
{
logStream << "Deleting array at address "
<< static_cast<void*>(array)
<< '\n';
delete[] array;
}
BalancedBST* balTreaaArray = new BalacnedBST[50]; // 파생 클래스 객체 배열
...
deleteArray(cout, balTreeArray); // 미정의 동작!!
결론
- C++ 언어 스펙에 의하면..
- 기본 클래스 포인터를 통해 파생 클래스 객체의 배열을 삭제한 결과는 "정의되지 않았다."
- 다형성과 포인터 산술 연산은 간단히 섞이는 성질의 것이 아니다.
- 허나, 배열 연산에는 거의 항상 포인터 산술 연산이 따라다닌다.
- 배열의 요소 접근은 포인터 산술 연산이기 때문이다.
- 즉, 배열과 다형성은 함께 고려할만한 대상이 아닌 것이다.
- 가능하면 어떤 구체 클래스를 상속하여 다른 구체 클래스를 만들지 않게끔 설계하자.(항목 33 참조)
- 즉, BST를 상속하여 BalancedBST를 만드는 식의 설계를 지양할 수 있다면 지양하자.
- 그러면 객체의 배열을 다형적으로 조작하는 실수를 피할 수 있을 것이다.
참조
728x90
'개발 > More Effective C++' 카테고리의 다른 글
[More Effective C++] 6. operator++ / operator-- (0) | 2024.08.06 |
---|---|
[More Effective C++] 5. 암시적 변환 지양하기 (0) | 2024.08.05 |
[More Effective C++] 4. 불필요한 기본 생성자 미제공하기 (0) | 2024.08.04 |
[More Effective C++] 2. C++ 스타일 캐스팅 (0) | 2024.08.02 |
[More Effective C++] 1. 포인터 vs 참조자 (0) | 2024.08.01 |
Comments