2. 항목 26 : 변수 정의는 늦출 수 있
는 데까지 늦추자
• 생성자 혹은 소멸자를 끌고 다
니는 타입으로 변수를 정의하
면 반드시 생성자 호출, 소멸
자 호출을 하는데 들어가는 비
용이 생긴다.
• 변수가 정의되었는데 상요되
지 않을 경우에도 쓸데없는 비
용이 생긴다.
• ->사용될 줄 알고 생성한 변수
가 사용이 안되는 경우가 생길
수 있다.
• 언뜻 보면 encrypted가 반드시 사용되는 변수인 것
같지만 if 문에서 걸리면 사용되지 않는 변수가 된
다.
3. 변수 정의는 꼭 필요해질 때 하자
• 조건에 걸려버리면 encrypted
는 쓸모없는 변수가 되어버리
므로, 꼭 필요해지기 전까지
encrypted의 정의는 미루는 것
이 좋다. • encrypted가 사용 될 수 있는 시점에 와야 비로소
변수로서 의미를 가지므로 다음과 같이 선언하면
변수 낭비의 비용이 발생하지 않는다.
4. • 주의할 점은 루프안에서의 문제인데 이때는
A : 루프 바깥족에 정의 -> 생성자 1 + 소멸자 1 +
대입 n
B : 루프 안쪽에서 정의 ->생성자 n + 소멸자 n
두 방법의 효율을 따져서 정한다.
정의와 동시와 초기화를 하는게
좋다
• 초기화 인자를 손에 넣기 전까
지 정의를 늦출 수 있는지 보
아야 한다.
-> 대입연산자를 이용하면 초
기화를 이용하는 것보다 비용
이 더 들어가기 때문에, 정의
와 동시에 초기화를 하면 기본
생성자 호출의 낭비를 막을 수
있다.
• 루프안에서는 일반적으로는
루프 바깥족에서의 정의하는
것이 효율이 좋다(대입에 들어
가는 비용이 생성자-소멸자 쌍
보다 더 적을 경우가 많다)
5. 항목 26 정리
• 변수 정의는 늦출 수 있는 때까지 늦추자
• 초기화 인자가 나올때까지, 객체 정의를 늦추자
• 루프안에서의 변수 정의는 케이스 바이 케이스
로 효율을 따져서 결정하자
6. 항목 27 : 캐스팅은 절약, 또 절약
• 캐스트에 항상 주의해야 한다.
• C스타일의 캐스트, C++스타
일의 캐스트 중 C++ 스타일의
캐스트를 쓰는 것이 더 좋다
-> 어떤 것인지 알아보기 쉽고
, 캐스트의 사용목적을 좀더
명확하게 알아 볼 수 있다.
• c스타일의 캐스트와, c++스타일의 static_cast를 통
해 double 타입의 a를 int타입으로 강제 형변환 시
켜준 예시
12. 항목 27 정리
• 되도록이면 캐스팅을 피하자
• dynamic_cast는 정말 신중하게 쓰자.
• 캐스팅이 반드시 필요하다면 함수 안에 숨길수
있도록 하자
• C 스타일보다 C++ 스타일의 캐스트를 쓰도록 하
자
13. 항목 28 : 내부에서 사용하는 객
체에 대한 ‘핸들’을 반환하는 코드
는 피하자• 클래스 멤버 데이터는 그 멤버
의 참조자를 반환하는 함수들
의 접근도에 따라 캡슐화가 정
해진다.
• 참조자 뿐만 아니라 핸들(참조
자, 포인터, 반복자 처럼 다른
객체에 손을 댈 수 있게 하는
매개자)을 반환하게 만들면 캡
슐화가 보장되지 않는다.
• 특히 private로 외부 공개가 금
지된 데이터에 대해서 핸들을
반환할 시 그 캡슐화가 깨질
수 있기때문에 주의해야 한다.
• 핸들을 반환하는 코드는 사용하면 안된다.
14. 반환타입에 const를 붙이면 수정
불가하게 만들 수 있다
• const키워드를 붙임으로써 오직 읽도록만 할 수
있다.
15. 항목 28 정리
• 어떤 객체의 내부요소에 대한 핸들( 참조자, 포인
터, 반복자)를 반환하는 것은 피하자
• 무효참조 핸들이 생기는 경우를 최소화 하자.
• 캡슐화 정도를 높이기 위해서 핸들 반환하는 것
을 피하자
16. 항목 29 : 예외 안전성이 확
보되도록 하자• 강력한 보장 : 함수 동작 중에 예외가 발생하면,
프로그램의 상태를 절대로 변경하지 않겠다는
보장. 이런 함수를 호출하는 것은 원자적인 동작
이라 한다.
• 예외불가 보장 : 예외를 절대로 던지지 않겠다는
보장. 약속한 동작은 언제나 끝까지 완수하는 함
수
• 기본적인 보장 : 함수 동작 중에 예외가 발생하면
, 실행 중인 프로그램에 관련된 모든 것들을 유요
한 상태로 유지. 어떤 객체나 자료구조도 더럽히
지 않으며, 일관성을 유지하게 한다.
17. 항목 29 정리
• 예외 안전성을 갖춘 함수는 실행 중 예외가 발생되
더라도 자원을 누출시키지 않는다.
• 예외 안전성 보장은 기본적인 보장, 강력한 보장,
예외 금지 보장이 있다.
• 강력한 예외 안전성 보장은 ‘복사-후-맞바꾸기’ 방
법을 써서 구현, 모든 함수에 대해 실용적인 것은
아니다.
• 어떤 함수가 제공하는 예외 안전성 보장의 강도는
그 함수가 내부적으로 호출하는 함수들이 제공하
는 가장 약한 보장을 넘지 않는다.
18. 항목 30 : 인라인 함수는 잘 따져
서 이해하자• 인라인 함수는 함수 호출문을 그
함수의 본문으로 바꿔치기
• 함수 호출 비용이 면제
• 메모리가 제한된 프로그램에서
는 코드가 커져서 문제가 발생할
수 있음
• inline은 컴파일러에 대해 ‘요청’
이지 ‘명령’이 아님
• 암시적인 인라인 방법은 클래스
정의 안에 함수를 바로 구현(정
의)
• 명시적인 방법에는 함수 정의 앞
에 inline키워드를 붙임
• GetAge멤버함수는 클래스 정의 내부에서 구현되
어있고, 이것은 곧 암시적인 인라인 요청을 하는 것
임을 뜻한다.
• Max함수라는 것은 명시적으로 inline키워드를 써서
인라인함수 요청을 컴파일러에게 했다.
19. C++에서의 인라인 함수
• 대부분의 C++ 프로그램에서 함수 인라인은 컴파일 타임에 진행
• 인라인이 끌고 오는 비용은 바로 코드 비대화
• 대부분의 컴파일러의 경우 아무리 인라인 함수로 선언(요청)을 했다 하더
라도, 컴파일러 자신이 보기에 복잡하거나 인라인에 적합하지 않다면 절
대로 인라인의 대상에 넣지 않음
• 가상함수는 절대로 인라인 해주지 않음
->virtual의 의미는 어떤 함수를 호출할지 결정하는 작업을 실행중에 한다
는 것인데 인라인은 그 위치에 호출된 함수를 끼워넣는 작업이다. 컴파일
러는 실행전에 그 위치에 함수의 코드를 끼워 넣어야 되는데 그 함수가 어
떤건지 알 수 없다.
• 생성자와 소멸자는 인라인하기에 좋지않다.
->동적으로 만들었다면 생성자에서 초기화 해주거나, 상속을 받았다면 기
본 클래스의 생성자를 호출해 준다든가, 멤버 데이터들을 초기화해준다거
나 하는 일들을 한다. 이런것들을 전부 인라인으로 처리해 버리면 호출되
는 함수들이 전부 코드로 들어가버리므로 똑같은 함수들을 여러개 가지는
꼴이 되어버릴 수 있다.
20. 항목 30 정리
• 함수 인라인은 작고, 자주 호출되는 함수에 대해
서만 하자
-> 디버깅 및 라이브러리의 업그레이드가 용이,
프로그램의 속도가 빨라질 가능성이 있음
• 되도록이면 아무것도 인라인하지말고( 컴파일러
가 알아서 인라인으로 적합한 것은 인라인으로
바꾸어줌), 인라인해야하는 경우는 정말 단순한
함수에 한해서만 해줌
21. 항목 31 : 파일 사이의 컴파일 의
존성을 최대로 줄이자
• 어떤 것이 컴파일 되려면 그것
에 속한 정보들이 있어야 하는
데 이때 쓰이는 지시자가
#include이다.
• #include는 파일과 헤더파일
들 사이에 컴파일 의존성을 엮
어버린다. 즉 이것에 엮여 있
는 모든 것들이 이것에 의존하
게 되는 것이다.
• 의존성이 높아져버리면 컴파
일이 꼬리에 꼬리를 물어 굉장
한 성능저하를 가져올 수 있다
.
• 위의코드만 가지고 Person클래스가 컴파일 되지
않는다. Person의 구현의 한 부분인 string, Date,
Address등 연관된 것들의 정보가 있어야 컴파일 된
다. 이때 쓰는 것이 #include 지시자이다. 즉
#include “date.h”, #include “address.h”, #include
<string> 선언되어야 한다.
22. 인터페이스와 구현을 둘로 나누
자• 정의부에 대한 의존성을 선언
부에 대한 의존성으로 바꿈
-> 컴파일 의존성을 최소화하
는 원리
• 객체 참조자 및 포인터로 충분
한 경우 객체를 직접 쓰지 않
는다.
• 할 수 있으면 클래스 정의 대
신 클래스 선언에 최대한 의존
하도록 한다.
->클래스를 사용하는 함수를
선언할 때는 그 클래스의 정의
는 굳이 가져오지 않아도 된다
.
• 선언부와 정의부에 대해 별도
의 헤더파일 제공
• 어떤 클래스를 사용하는 함수를 선언할 때는 그 정
의는 필요 없음
• 또는 이렇게 헤더파일을 만드는데 선언만 되어있는
헤더파일만으로도 가능
23. 항목 31 정리
• 컴파일 의존성을 최소화하자
• 컴파일 의존성을 최소화하는 아이디어
-> ‘정의’ 대신에 ‘선언’에 의존하게 만들자
• 라이브러리 헤더는 그 자체로 모든 것을 가줓어
야 하며 선언부만 갖고 있는 형태여야 한다.
24. 항목 32 : public상속은 is-a관계
• public 상속은 “is-a”를 의미한
다
• Cat클래스를 Animal 클래스로
부터 상속을 통해 파생시켰다
면 이 뜻은 ‘Cat 타입으로 만들
어진 모든 객체는 Animal타입
의 객체이지만 그 반대는 성립
하지 않는다’ 이다
• Animal객체가 쓰일 수 있는 모
든 곳에는 Cat객체도 쓰일 수
있다고 단정하는 것
• cat is a Animal 이 되지만 반대인 Animal is cat은
말이 안된다.
25. 항목 32 : public상속은 is-a관계
• Bird 객체인 a는 수영을 할 수
없다.
• Penguin 객체인 b는 수영을
할 수 있다.
• Penguin객체인 b는 날 수 없
지만 Bird에 기본 함수는 날 수
있다고 되어있기에, 가상함수
를 이용하여 재정의
-> 인간의 언어 때문에 클래스
설계에 있어 오류를 범하는 경
우가 많이 있다. 설계시 주의
해야 하는 사항
26. 항목 31 정리
• public 상속의 의미는 “is-a” 관계이다. 기본 클래
스에 적용되는 모든 것들이 파생 클래스에도 그
대로 적용이 된다.
-> 이는 파생 클래스 객체도 기본객체의 일종으
로 보기 때문이다.
27. 항목 33 : 상속된 이름을 숨기는
일을 피하자
• C++ 컴파일러는 유효범위 안
에서 어떤 변수의 이름을 만나
면 일단 자신이 처리하는 유효
범위를 뒤져서 같은 이름이 있
는지 확인.
• 그 유효범위에 있으면 더이상
탐색하지 않음
• 그 유효범위에 없다면 다음 영
역의 유효범위를 탐색
• 컴파일러는 자신이 처리하고있는 곳의 유효범위부
터 탐색해 나간다.
28. 클래스에서의 이름 가리기
• 파생 클래스 Dervied 의 mf1은
Base의 mf1(int)를 가린다.
• 파생 클래스 Dervied 의 mf3
는 Base의 mf3(), mf3(double)
을 가린다.
-> 이러한 이유는 파생클래스
에서 멀리 떨어져 있는 기본
클래스의 오버로드 버전을 상
속하는 것을 ‘실수’로 간주하
겠다는 컴파일러의 의도 때문
이다.
• Derived클래스의 mf1, mf3로 인해 오버로드 된
Base 클래스의 mf1, mf3또한 가려지게 된다.
29. using 키워드 이용
• 파생 클래스에 의해 가려진 기
본 클래스의 오버로드된 함수
들은 using 키워드를 통해 끄
집어낼 수 있다.
• 즉, 오버로드된 함수들 중에
재정의를 하고 싶은것이 있다
면 파생클래스에서 재정의를
하고, using 키워드를 붙여주
면 된다.
• using 키워드를 통하여 기본클래스의 mf1, mf3의
이름이 derived영역에서도 유효하게 되었다
30. 항목 33 정리
• 파생 클래스의 이름은 기본 클래스의 이름을 가
린다
• public 상속에서의 이런 이름 가림 현상은 바람직
하지 않다
• 가려진 이름을 다시 볼 수 있게 하는 방법으로
using 선언 혹은 전달 함수를 쓸 수 있다.
31. 항목 34 : 인터페이스 상속과 구
현상속의 차이 알기
• pubilc상속의 개념은 함수 인
터페이스의 상속과 더불의 함
수 구현의 상속
• 인터페이스 -> 함수의 선언
구현 -> 함수의 정의
• public으로 상속을 받았다는 것은 기본적으로 인터
페이스 + 구현 까지 상속을 받은 것이다. Derived
는 Base를 public으로 상속받으므로 Base의 인터
페이스 및 구현을 상속 받은 것.
32. 순수가상 함수는 인터페이스 상
속을 뜻한다
• 순수 가상 함수를 상속받는 파
생 클래스에서는 그 가상함수
를 다시 선언해야 한다.
• 순수 가상 함수는 전형적으로
추상 클래스 안에서는 정의를
갖지 않는다.
• 순수 가상 함수를 선언하는 목
적은 파생 클래스에게 함수의
인터페이스만을 물려주는 것. • 부모 클래스인 Shape에서 Draw는 순수 가상 함수
로 선언. 즉 파생클래스인 Triangle에서 다시 선언
및 구현을 해주어야 한다.
33. 비순수가상 함수는 인터페이스 상속
과 더불어 그 함수의 기본적 구현을
물려받게 함
• 비순수 가상 함수는 인터페이
스와 더불어 기본적 구현을 물
려받게 하는 방법
• 파생 클래스에서 따로 재정의
하지 않아도 된다
->기본적 구현을 물려받았기
때문에
• 파생클래스에서 따로 재정의
해도 된다
-> 가상함수로 인터페이스 상
속과 더불어 구체적인 구현도
가능하기 때문에
• 기본 클래스의 Error은 비순수가상 함수로 이에대
한 인터페이스와 기본적인 구현을 물려받음
34. 비가상 함수는 인터페이스와 필
수적인 구현까지 물려받음
• 비가상 함수를 선언하는 목적
은 파생 클래스가 함수 인터페
이스와 더불어 그 함수의 필수
적인 구현을 물려받게 하는 것
• 비가상 함수는 클래스 파생에
관계없이 동작에 있어 변하는
것이 없을 때 사용
• 즉, 파생클래스에서 재정의 하
는 것이 아니다.
• SetName과 GetShapeName함수는 비가상 함수인
데, 파생클래스라 하더라도 이름을 정하고 받아오
는 함수는 동작에 변화가 없으므로 비가상 함수로
선언.
35. 항목 34 정리
• 인터페이스 상속은 구현상속과 다르다
• public상속은 기본 클래스의 인터페이스를 모두
물려 받는다
• 순수 가상 함수는 인터페이스만 상속
• 비순수 가상 함수는 인터페이스 상속과 더불어
기본 구현의 상속도 가능
• 비가상 함수는 인터페이스 상속과 더불어 필수
구현의 상속
36. 항목 35 : 가상 함수 대신 쓸 것들
도 생각해두자
• 비가상 인터페이스 관용구를 사용하자 : 공개되
지 않은 가상 함수를 비가상 public멤버 함수로
감싸서 호출
• 가상 함수를 함수 포인터 데이터 멤버로 대체하
자
• 가상 함수를 tr1::function 데이터 멤버로 대체하
여 호환되는 시그너처를 가진 함수호출성 개체
를 사용할 수 있도록 하자
• 한쪽 클래스 계통에 속해 있는 가상 함수를 다른
쪽 계통에 속해 있는 가상 함수로 대체하자
37. 항목 35 정리
• 가상 함수 대신에 쓸 수 있는 다른 방법으로 NVI
관용구 및 전략 패턴을 들 수 있다 이중 NVI 관용
구는 그 자체가 템플릿 메서드 패턴의 한 예시
• 객체에 필요한 기능을 멤버 함수로부터 클래스
외부의 비멤버 함수로 옮기면, 그 비멤버 함수는
그 클래스의 public 멤버가 아닌 것들을 접근할
수 없다는 단점이 생김
• tr1::function 객체는 일반화된 함수 포인터처럼
동작. 이 객체는 주어진 대상 시그너처와 호환되
는 모든 함수호출성 개체 지원
38. 항목 36 : 상속받은 비가상 함수를
파생 클래스에서 재정의하는 것은
절대 금물• 비가상 함수는 정적 바인딩
-> 빌드 중에 이름, 식별자, 값, 속
성들의 내부요소를 정의.
• 가상 함수는 동적 바인딩
-> 실행중에 이름, 식별자, 값, 속성
들의 내부요소를 정의.
• 자기 자신의 객체가 아닌 객체를
가리키는 포인터 타입에 의해 어떤
함수를 호출할 지 결정.
• 비가상 함수를 public으로 상속받
으면 인터페이스와 필수 구현을 그
대로 물려받음 -> 파생클래스에서
재정의하는 것은 모순(Triange is a
Shape이 성립하지 않음)
• Shape클래스에서 비가상 함수를 구현하고 이를
Triangle클래스가 상속을 받았는데, 다시 그 비가상
함수를 재정의 하고 있다. 해당 객체 자신( Triangle
객체 a ) 이 아닌 그것을 가리키는 포인터 pT에 의
해 좌우된다.
39. 항목 36 정리
• 상속받은 비가상 함수를 재정의하는 일은 절대
로 하면 안된다.
• public상속 관계의 “is- a” 관계에 모순이 생김
• 재정의 할 필요가 있는 함수라면 가상 함수로 정
의하는 것이 맞다.
40. 항목 37: 어떤 함수에 대해서도 상속
받은 기본 매개변수 값은 절대로 재정
의하지말자
• 비가상 함수는 정적 바인딩
-> 빌드 중에 이름, 식별자, 값,
속성들의 내부요소를 정의.
• 가상 함수는 동적 바인딩
-> 실행중에 이름, 식별자, 값,
속성들의 내부요소를 정의.
• 기본 매개변수는 정적 바인딩
• Triangle의 객체를 생성해서 Triangle의 func() 를
실행하면 size = 1이 되어 나온다. 즉, Triangle클래
스에서 매개변수를 재정의한 것이 의미가 없다는
것이다.(매개변수는 기본 클래스 것을 이용) -> 꼬
여버림
41. 비가상 인터페이스를 이용하여
해결
• 파생 클래스에서 재정의할 수
있는 가상 함수를 private 멤버
로 둔다.
• 이 가상 함수를 호출하는
public비가상 함수를 기본 클
래스에 만든다.
• 비가상 함수가 기본 매개변수
를 지정할 수 있게 한다.
• func를 비가상함수로 만들고, 재정의할 수 있는 함
수 Dofunc를 만들어 호출. 비가상 함수가 기본 매개
변수를 지정하도록 할 수 있음.
42. 항목 37 정리
• 상속받은 기본 매개변수 값은 절대로 재정의하
면 안된다.
• 기본 매개변수는 정적으로 바인딩
• 가상함수는 동적으로 바인딩
• 함수호출이 꼬여버리는 경우가 생길 수 있다.
43. 항목 38: “has-a”혹은 “is-implemented-in-
terms-of”를 모형화할 때는 객체 합성을
사용
• 합성이란 어떤 타립의 객체들
이 그와 다른 타입의 객체들을
포함하고 있을 경우에 성립하
는 그 타입들 사이의 관계
• 합성 대신에 레이어링, 포함,
통합, 내장 등으로도 쓴다.
• …has a~ : …은 ~를 가진다
• …is-implemented-in-terms-
of~ : …은 ~를 써서 구현된다.
• Person 객체는 이름, 주소, 핸드폰전화번호 등을
가지고 있는 객체이므로, Person과 string
m_Name, Address m_Address, PhoneNumber
m_celPhone 은 “has - a “ 관계.
• Person has a name;
• Person has a Address;
44. 과
• public 으로 상속을 받는다면
이는 is-a관계이다.
• STL의 set 클래스를 만드는데
list STL을 이용하고자 한다.
• 이때 set 은
set is-implemented-in-terms-
of list가 되는 것이고 이 두 관
계가 되는 것이다.
• 위의 관계로 is-a로 해석해버리면 set is a list가 되
어야 하는데 list 는 중복을 허용하지만 set은 그렇
지 않다. 즉 성립하지 않음을 알 수 있다.
• 밑의 관계로 is-implemented-in-terms-of가 되면 set
은 list를 이용하여 만들어졌다 로 자연스럽게 해석
할 수 있다.
45. 항목 38 정리
• 객체 합성의 의미는 public 상속이 가진 의미와
완전히 다르다
• 응용 영역에서 객체 합성의 의미는 has-a 이다
• 구현 영역에서 객체 합성의 의미는 is-
implemented-in-terms-of이다.
46. 항목 39: private 상속은 심사숙고
해서 구사하자
• private 상속은 분명히 is-a를
뜻하지 않는다.
• private로 상속 받으면 컴파일
러는 일반적으로 파생 클래스
객체를 기본 클래스 객체로 변
환하지 않는다.
• 기본 클래스로부터 물려받은
멤버는 파생 클래스에서 모조
리 private멤버가 된다.
• private상속의 의미는 is-
implemented-in-terms-of, 인터
페이스는 물려받지 못하고 구
현만 물려받을 수 있다.
• S는 더이상 Person으로 간주되지 않는다. 다만 S
는 Person의 몇 가지 특성을 사용한다는 뜻이다.
47. 객체 합성과 private상속의 차이
• 객체 합성도 is-implemented-
in-terms-of의 관계를 갖는다.
• 되도록이면 객체 합성을 사용
하고, 꼭 필요한 경우에만
private사용
-> 꼭 필요한 경우라 하면 비
공개 멤버를 접근할 때 혹은
가상 함수를 재정의할 경우.
• 어떤 클래스에서 필요한 기능
이 있는데 이것을 public상속
을 받는다면 is-a 관계가 되어
모순이 일어난다. 따라서 이렇
게 어떤 기능을 이용할 때에는
private 상속을 받을 수 밖에
없다.
• private상속은 public상속과 객체합성을 이용하여
피할 수 있다. 하지만 관계는 더 복잡해진다.
48. 항목 39 정리
• private상속의 의미는 is-implemented-in-terms-
of이다
• 파생 클래스 쪽에서 기본 클래스의 protected 멤
버에 접근해야 할 경우, 상속받은 가상 함수를 재
정의해야 할 경우에 private 상속을 고려해보아
야 함
• 객체 합성과 달리, private 상속은 공백 기본 클래
스 최적화(EBO)를 활성화시킬 수 있다.
49. 항목 40: 다중 상속은 심사숙고해
서 사용하자
• 다중 상속은 단일 상속보다 구
조가 복잡
• 다중 상속하면 둘 이상의 기본
클래스로부터 똑같은 이름( 멤
버 함수, 멤버 변수 등 )을 물
려받을 가능성이 생긴다.
• Son 객체인 me는 Father 와 Mother의 다중 상속을
받고 있고, 다시 Father 와 Mother 는 Person으로
부터 단일 상속을 받는다. 이때 Son 객체의 Do()를
호출 하면 Father의 것인지 Mother의 것인지 알 수
없기에 에러가 발생한다.
50. 모호성을 없애기 위해 호출할 기
본 클래스의 함수를 손수 지정• 모호성을 없애기 위해 호출할
기본 클래스를 지정해주어야
한다.
• 만약 데이터멤버의 중복생성
을 원한 것이 아니었다면 데이
터 멤버를 가진 클래스를 가상
기본 클래스로 만들어야 한다.
-> 기본 클래스가 상속되는 경
로 갯수만큼 데이터가 중복생
성 되는 걸 막기 위해서
• 가상 상속을 사용하는 클래스
는 가상 상속을 쓰지 않는 클
래스보다 크기가 크고, 속도도
느리다
-> 가상 상속은 비싸다
• me.Father::Do()로 호출할 기본 클래스를 지정해줌
으로써 어떤 함수를 호출할 지 컴파일러가 알게되
어, 호출이 된다.
51. 가상 상속
• 가상 상속을 하지 않으면 Fater와
Mater 클래스를 다중상속 받는
Son객체가 생성 될 때
1. Father와 Mother 의 부모인
Person클래스가 각각 생성
2. Father와 Mother를 상속받음
• 만약 자식에서 Person의 허용된
데이터 및 함수를 읽고자 할 때,
Father의 것인지, Mother의 것인지
알 수 없어서 모호함 -> 에러
• virtual 로 상속 받으면 Father와
Mother의 부모인 Person을 한 번
만 생성 -> 조상이 Person하나이
므로 Person의 허용된 데이터 및
함수 사용 가능
• 가상상속을 통하여 조상의 함수를 바로 호출 가능
52. 항목 40 정리
• 다중 상속은 단일 상속보다 확실히 복잡하다
• 모호성이 생길 여지가 있다
• 가상 상속이 필요해질 때가 있는데, 가상 상속을
사용하면 크기, 속도 면에서 비가상 상속과 비교
하여 좋지 않다
• 가상 상속 시 가상 기본 클래스에는 데이터를 두
지 않는 것이 좋다 -> 초기화 및 대입 연산의 복
잡도가 커지기 때문에