항목 3 : 배열과 다형성은 같은 수준으로 놓고 볼 것이 아니다.

  • 상속성이 주는 혜택 : 다형성
  • 파생 클래스 객체의 배열을 기본 클래스 포인터/참조자를 통해 조작
    • 실제 동작이 바라던 대로가 아니다!
  • 기본 클래스 배열이 들어갈 자리에 파생 클래스가 들어가면 발생하는 문제
    1. 파생 클래스의 크기를 기본 클래스의 크기로 가정하므로 미정의 결과가 나타난다.
    2. 기본 클래스의 소멸자를 호출하므로 파생 클래스가 온전히 삭제되지 않는다.(미졍의 결과)
  • 다형성 / 포인터 산술 연산은 간단하지 않다.
  • 배열 연산에는 거의 항상 포인터 산술 연산이 따라다닌다.
  • 즉, 배열과 다형성은 물과 기름의 관계이다.

  • 구체 클래스를 상속하여 다른 구체 클래스를 만들지 않게끔 설계하면 실수를 저하시킨다.(33)

항목 4 : 쓸데 없는 기본 생성자는 그냥 두지 말자

  • 기본 생성자 : 아무런 인자도 받지 않고 호출될 수 있는 생성자

  • 기본 생성자가 없는 클래스 사용상의 주의사항
    1. 배열을 생성할 때 : 일반적으로 배열의 요소 객체에 생성자 매개변수를 지정할 수 없다.
      • 해결법
        1. 배열을 힙에 만들지 않을 때는 배열이 정의된 위치에서 매개변수를 직접 삽입한다.
      • ex)
         EquipPiece bestPieces[] = { EquipPiece(ID1), EquipPiece(ID2), ... }; 
        
        1. 포인터의 배열 사용
      • ex) cpp EquipPiece* bestPieces[10]; EquipPiece** bestPieces = new EquipPiece*[10]; for(int i = 0 ; i < 10 ; i++) bestPieces[i] = new EquipPiece(IDNum);
      • 배열 내 포인터의 객체 삭제를 잊으면 안된다. »+ 필요 메모리 사용량이 증가한다.(객체 메모리 + 포인터 공간(추가 필요)) -> 비가공 메모리 할당 후 메모리 지정 new로 그 메모리 안에 객체를 생성하게 하면 메모리 공간을 줄일 수 있다.(8)
      • 대부분의 프로그래머가 이것과 친하지 않음.
      • 객체 삭제 시 소멸자를 손으로 직접 호출해야 한다.
      • operator delete[]를 호출해 원래의 비가공 메모리를 직접 해제해야 한다.
    2. 많은 템플릿 기반 컨테이너 클래스에 먹일 수가 없다.
      • 컨테이너 클래스를 인스턴스화 하기 위해서는 템플릿 매개변수로 들어가는 타입이 기본 생성자를 가지고 있어야 하기 때문이다.(클래스 / 구조체 등의 복합 타입 외에 int, double 같은 원시 타입도 기본 생성자를 가지고 있다.)
    3. 가상 기본 클래스에 기본 생성자가 없으면 개발에 쓰기 어렵다.
      • 가상 기본 클래스의 생성자 매개변수를 생성되는 객체의 파생클래스에서 제공해야 하기 때문이다. »+ 즉, 파생클래스가 기본클래스의 생성자 매개변수의 리스트와 각 매개변수의 의미를 알고 직접 제공해야 한다! 귀찮..
  • 모든 클래스에 기본 생성자를 넣는다?
    • 다른 멤버 함수가 복잡해진다. 객체의 멤버 데이터가 제대로 초기화 되었는지 보장할 수가 없다.
    • 초기화하지 않은 멤버데이터에 임의의 값을 넣었을 때 -> 거의 모든 멤버 함수에 초기화 했는지(ex)ID번호) 체크해야 한다.
    • 클래스 효율 저하 : 초기화 검사 시간만큼 실행속도 저하, 초기화 검사 코드만큼 실행파일 / 라이브러리 크기 증가, 초기화 검사 실패 처리 코드도 생각해야 한다.
  • 즉 쓸데없는 상황에서는 기본 생성자를 피하자.