스토리텔링 개발자

[More Effective C++] 3. 다형성 객체의 배열 지양하기 본문

개발/More Effective C++

[More Effective C++] 3. 다형성 객체의 배열 지양하기

김디트 2024. 8. 3. 11:25
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를 만드는 식의 설계를 지양할 수 있다면 지양하자.
    • 그러면 객체의 배열을 다형적으로 조작하는 실수를 피할 수 있을 것이다.

 

 

 

참조

 

 

[Effective C++] 16. new, delete 짝 맞춤 문제

항목 16. new 및 delete를 사용할 때는 형태를 반드시 맞추자   new와 delete의 내부동작 순서new 연산자operator new 함수 내부에서 메모리를 할당한다.할당된 메모리에 대해 한 개 이상의 생성자 호출된

delightlane.tistory.com

 

728x90
Comments