["MoreEffectiveC++"] || [[TableOfContents]] || = Basic = == Item 1: Distinguish between pointers and references. == * Item 1: Pointer와 Reference구별해ë¼. Pointers use the "*" and "->" operators, references use "." [[BR]] ëŠë‚Œì´ 오는 ì˜ˆì œë“¤![[BR]] {{{~cpp char *pc = 0; char& rc = *pc; }}} 프로그래머 초급ìžë©´ 알수 있는 바보 ì§“ì´ë‹¤. 하지만 범하기 쉬운게 ë¬¸ì œë‹¤. {{{~cpp string& rs; // Reference(참조)ê°€ 초기화가 ë˜ì§€ 않아서 ì—러 string s("xyzzy"); // ì´ê±´ ëœë‹¤ ì‹ ê¸°í•˜ë„¤ string& rs = s; }}} ì•„ì§ stringì¨ë³¸ì í•œë²ˆë„ ì—†ë‹¤. 반성.. {{{~cpp void printDouble(const double& rd) { cout << rd; // rdì— ê´€í•œ 특별한 검사 í•„ìš” 없다. reference니까. } //////////////////////////////////////////////////////////////////// void printDouble (const double* pd) { if (pd){ cout << *pd // pdê°€ nullì¸ì§€ 검사 해야 한다. pointer니까. } } }}} pointerì˜ ìœ ì˜ ì‚¬í•ì¸ nullì— ê´€í•œ ë‚´ìš©ì„ ë‹¤ì‹œ ì•Œë ¤ì¤€ë‹¤. {{{~cpp string s1("Nancy"); // ì´ì œëŠ” 무슨 퀴즈 같다. string s2("Clancy"); string& rs = s1; string* ps = &s1; rs = s2; // s1ì˜ ì¸ìžê°€ "Clancy" 로 ë°”ë€ë‹¤ëŠ” ì˜ë¯¸ë‹¤. ps = &s2; // 그냥 í¬ì¸í„°ë§Œ 세팅하는 거다. // ì´ê±¸ë¡œ ps는 s2를 ê°€ë¦¬í‚¤ê³ s1ì—는 아무런 ì˜í–¥ì„ ë¼ì¹˜ì§€ 않는다. }}} 사견: Call by Value 보다 Call by Reference와 Constì˜ ì¡°í•©ì„ ì„ í˜¸í•˜ìž. ì €ìžì˜ Effective C++ì— ì „ë°˜ì 으로 언급ë˜ì–´ ìžˆê³ , 프로그래ë°ì„ 해보니 ê´œì°®ì€ íŽ¸ì´ì—ˆë‹¤. 단 returnì—서 ë§ì½ì´ ìƒê¸°ëŠ”ë°, 현재 ë‚´ ìƒê°ì€ returnì— ëŒ€í•´ì„œ 회ì˜ì ì´ë‹¤. 그래서 나는 COMì‹ í‘œí˜„ì¸ in, out ì ‘ë‘어를 사용해서 아예 ì¸ìžë¥¼ 넘겨서 관리한다. C++ì˜ ê²½ìš° returnì— ì˜í•´ ê°ì²´ë¥¼ Call by Reference하면 {} 를 벗어나는 ì…ˆì´ ë˜ëŠ”ë° ì–´ë””ì„œ 파괴ë˜ëŠ” 것ì¸ê°€. 다 공부가 부족해서야 ì© --; ì§€ì—함수 안ì—서 ì§€ì— ê°ì²´ë¥¼ ìƒì„±í•˜ì—¬ Reference로 ë¦¬í„´í• ê²½ìš° ì§€ì— í•¨ìˆ˜ê°€ 반한ë˜ë©´ ì§€ì— ê°ì²´ëŠ” 없어질 것ì´ê³ , 리턴ë˜ëŠ” Reference는 존재하지 않는 ê°ì²´ì— 대한 다른 ì´ë¦„ì´ ë 것ì´ë©°, ê²½ìš°ì— ë”°ë¼ì„œ 컴파ì¼ì€ ë 지모르나 ë‚˜ìœ ì½”ë“œë¼ê³ 하네요.-ì°¨ì„- ì˜¤í•´ì˜ ì†Œì§€ê°€ 있ë„ë¡ ê¸€ì„ ì ì–´ 놨군요. in, out ì ‘ë‘어를 ì´ìš©í•´ì„œ reference로 넘길 ì¸ìžë“¤ì—서는 inì— í•œí•˜ì—¬ reference, outì€ pointer로 new, delete로 ë™ì 으로 ê´€ë¦¬í•˜ëŠ”ê²ƒì„ ì˜ë„한 ë§ì´ì—ˆìŠµë‹ˆë‹¤. ì „ì— í”„ë¡œì íŠ¸ì— ì´ëŸ°ì‹ì˜ 프로그래ë°ì„ ì ìš© 시켰는ë°, 함수 ë‚´ë¶€ì—서 í¬ì¸í„°ë¡œ 사용하는 것보다 inì— í•´ë‹¹í•˜ëŠ” ê°ì²´ 사용 ì½”ë”©ì´ íŽ¸í•˜ë”êµ°ìš”. ê·¸ë¦¬ê³ ë§ì”€í•˜ì‹ 대로, MEC++ ì „ë°˜ì— ì§€ì—ê°ì²´ë¡œ ìƒì„±í•œ Referneceë¬¸ì œì— ê´€í•œ ì–¸ê¸‰ì´ ìžˆëŠ”ë°, ì´ê²ƒì˜ 관리가 C++ì˜ ê°€ìž¥ í° ë²½ìœ¼ë¡œ 작용하는 ê²ƒì´ ì•„ë‹ê¹Œ ìƒê°ì´ ë©ë‹ˆë‹¤. OOP ì ì´ë ¤ë©´ ë°˜í™˜ì„ ê°ì²´ë¡œ 해야 하는ë°, ì´ë¥¼ í¬ì¸í„°ë¡œ 넘기는 ê²ƒì€ ì›ì¹™ì 으로 ê°ì²´ë¥¼ ë„˜ê¸´ë‹¤ê³ ë³¼ìˆ˜ ì—†ê³ , í•´ì œ ë¬¸ì œê°€ ë°œìƒí•˜ë©°, reference로 넘기면 ë§ì”€í•˜ì‹ ë°ë¡œ, 해당 scopeê°€ 벗어나면 언어ìƒì˜ lifetimeì´ ë난 것ì´ë¯€ë¡œ ì˜ì—ì— ëŒ€í•œ 메모리 ì ‘ê·¼ì„ OSì—서 막ì„ì§€ë„ ëª¨ë¦…ë‹ˆë‹¤. 단, inlineì— í•œí•˜ì—¬ëŠ” ì´ì•¼ê¸°ê°€ 달ë¼ì§‘니다. (inlineì˜ ì½”ë“œ êµì²´ê°€ compilerì— ì˜í•˜ì—¬ ê²°ì •ë˜ë¯€ë¡œ ì´ê²ƒë„ ì—시 모호해 집니다.) 아예 COMì—서는 OOPì—서 ë²—ì–´ 나ë”ë¼ë„, 범용ì 으로 ì“°ì¼ìˆ˜ 있ë„ë¡ CìŠ¤íŽ™ì˜ í•¨ìˆ˜ì™€ ê°™ì´ in, out ì˜ ì ‘ë‘어와 해당 ì ‘ë‘어는 pointer로 하는 ê·œì¹™ì„ ì„¸ì›Œë†“ì•˜ì§€ìš”. ì´ ì„¤ê³„ê°€ C#ì—서 buil-in typeì˜ scalarí˜•ì— í•´ë‹¹í•˜ëŠ” 것까지 ë°˜ì˜ëœ ê²ƒì´ ì¸ìƒì ì´ ì—ˆìŠµë‹ˆë‹¤.(MSê°€ 초기 .net세미나ì—서 ì´ ë•Œë¬¸ì— String ì—°ì‚° ì°¨ì´ê°€ 10~20ë°° ì •ë„ ë‚œë‹¤ê³ ê´‘ê³ í•˜ê³ ë‹¤ë…”ì—ˆëŠ”ë°, 지금 ìƒê°í•´ ë³´ë©´ 다 부질없는 ì´ì•¼ê¸° 같습니다.) -ìƒë¯¼ == Item 2 : Prefer C++ style casts. == * Item 2 : C++ 스타ì¼ì˜ í˜•ë³€í™˜ì„ ê¶Œìž¥í•œë‹¤. C style cast 방법 {{{~cpp (type) expression }}} C++ style cast {{{~cpp static_cast<type>(expression) const_cast<type>(expression) dynamic_cast<type>(expression) reinterpret_cast<type>(expression) }}} * ''static_cast<type>(expression)''는 ê¸°ì¡´ì˜ C styleì—서 사용하는 ''(type)expression'' 와 ë™ì¼í•˜ë‹¤. [[BR]] 다른 cast ë¬¸ë²•ì€ const와 classê°€ ê³ ë ¤ëœ C++ style castì—°ì‚°ìž ì´ë‹¤. * ''const_cast<type>(expression)ì˜ˆì œ'' {{{~cpp class Widget{ ...} class SpecialWidget:public Widget{...} void update( SpecialWidget *psw); SpecialWidget sw; const SpecialWidget& csw = sw; update(&csw); // 당연히 ì•ˆë¨ constì¸ìžì´ë¯€ë¡œ 변환(풀어주는 ì¼) 시켜 주어야 한다. update(const_cast<SpecialWidget*>(&csw)); // ì˜³íƒ€ì¿ ë‚˜ update((SpecialWidget*)&csw); // C styleì¸ë° 잘 ëŒì•„간다. // C++는 Cì™€ì˜ í˜¸í™˜ì„± ê³ ë ¤ë¥¼ 위한 것ì´ë¯€ë¡œ 위와 ê°™ì´ // ë™ìž‘ 하지만 명시ì ì´ì§€ ëª»í•œë©´ì´ ì§€ì ëœë‹¤. Widget *pw = new SpecialWidget; update(pw); update(const_cast<SpecialWidget*>(pw)); // error! // const_cast<type>(expression) 는 // ì˜¤ì§ ìƒìˆ˜(constness)나 변수(volatileness)ì— ì˜í–¥ì„ 미친다. // ì´ëŸ°ë§ 하면 다 가능한 듯 ì‹¶ê³ static_cast 와 ì°¨ì´ê°€ 없는 것 // ê°™ì€ë° ì˜†ì˜ ì†ŒìŠ¤ 처럼 down castê°€ 불가능하다. }}} ìœ„ì— ì˜ˆì œ ì´ì–´ì„œ ìƒê° * ''dynamic_cast<type>(expression)'' ì˜ˆì œ {{{~cpp Widget *pw ... update( dynamic_cast<SpecialWidget*>(pw)); // 옳다. // const_cast ê°€ down castê°€ 불가능 한 ëŒ€ì‹ ì— dynamic_cast 는 ë§ê·¸ëŒ€ë¡œ // 해당 부모 ê°ì²´ì˜ í¬ì¸í„°ì— ìžì‹ ê°ì²´ê°€ 가르켜 있으면 í˜•ë³€í™˜ì´ ê°€ëŠ¥í•˜ë‹¤. // 불가능 하면 null ì„ ë°˜í™˜í•´ì£¼ëŠ” 기특한 ì—í• ì´ í•µì‹¬ì´ë‹¤. void updateViaRef(SpecialWidget& rsw); updateViaRef(dynamic_cast<SpecialWidget&>(*pw)); // 옳다. // referenceì—ì„œë„ ì‚¬ìš© 가능하다? 그럼 불가능 í• ì‹œì˜ ì²˜ë¦¬ëŠ”? // ì´ëŸ´ë•ŒëŠ” 예외(exception)ì„ ë°œìƒì‹œì¼œ 준다. }}} * ''reinterpret_cast<type>(expression)'' ì€ ì°¨í›„ 다시 ì½ì€ë’¤ ì •ë¦¬í•œë‹¤. * C ì—서 ì§€ì›í•˜ì§€ ì•Šì„ ê²½ìš° ë‹¤ìŒ ë§¤í¬ë¡œë¥¼ 사용하여 {{{~cpp #define static_cast(TYPE, TEXPR) ((TYPE) (EXPR)) #define const_cast(TYPE, TEXPR) ((TYPE) (EXPR)) #define reinterpret_cast(TYPE, TEXPR) ((TYPE) (EXPR)) }}} ì´ë ‡ê²Œ 구현 해서 대비하는걸 추천한다. (dynamic_cast 는 Cì˜ ì ˆì°¨ì 프로그래ë°ì—서 등장 불가) {{{~cpp double result = static_cast(double, firstNumber)/ secondNumber; update(const_cast(SpecialWidget*, &sw)); funcPtrArray[0] = reinterpret_cast(FuncPtr, &doSomething); }}} == Item 3: Never treat arrays polymorphically == * Item 3: ì ˆëŒ€ë¡œ! í´ëž˜ìФ ê°„ì˜ ë‹¤í˜•ì„±ì„ í†µí•œ ë°°ì—´ ì·¨ê¸‰ì„ í•˜ì§€ ë§ë¼ 다른거 í•„ìš” 없다 ì´ ì˜ˆì œ ë³´ë©´ ì•„ì°¨ 싶다. {{{~cpp class BST { ... }; class BalancedBST : public BST { ... }; }}} ì´ëŸ° í´ëž˜ìŠ¤ë¥¼ ì„ ì–¸í–ˆë‹¤. ê·¸ë¦¬ê³ ë‹¤ìŒê³¼ ê°™ì€ í•¨ìˆ˜ë¡œ 해당 í´ëž˜ìŠ¤ì˜ ë°°ì—´ì„ ì‚¬ìš©í•œë‹¤ê³ ê°€ì •í•˜ìž {{{~cpp void printBSTArray( ostream& s, const BST array[], int numElements) { for ( int i = 0; i < numElements; ++i ){ s << array[i]; } } }}} ê·¸ë¦¬ê³ ë‹¤ìŒê³¼ ê°™ì´ ì‚¬ìš©í•œë‹¤. {{{~cpp BST BSTArray[10]; ... printBSTArray(cout, BSTArray, 10); // 올바르게 ìž‘ë™í•œë‹¤. 아무 ë¬¸ì œ 없다. ////////////////////////////////////// BalancedBST bBSTArray[10]; ... printBSTArray(cout, bBSTArray, 10); // 과연 올바르게 ìž‘ë™í•˜ëŠ”ê°€? }}} ìœ„ì˜ ë‘번째 í˜¸ì¶œì˜ í´ëž˜ìФ ìƒì†ì˜ 다형ì ì„±ì§ˆì„ ì´ìš©í•œ 함수 ì´ìš© 즉 {{{~cpp printBSTArray( cout, bBSTArray, 10 ); }}} ì€ ì •ë§ ìµœì•…ì˜ ê²°ê³¼ë¥¼ 불러 들ì¸ë‹¤. C++ì—ì„œì˜ ë°°ì—´ì€ '''array[i]''' ì˜ ì˜ë¯¸ëŠ” '''*(array+i)''' ì¸ë° ì´ê²ƒì˜ 주소 ì¶”ì ì„ ìœ„í•´ì„œ 엄밀히 따지면 [[BR]] '''*(array+ ( i *sizeof(an object in the array) )''' [[BR]] 로 사용한다. ëŠë‚Œì´ ì˜¤ê² ì§€! 당연히 ìƒì†ì‹œ child는 parent보다 í° ê²½ìš°ê°€ 다반사ì´ê³ ë°°ì—´ì˜ ìœ„ì¹˜ ì¶”ì ì´ ì—‰ë§ ì§„ì°½ì´ ë˜ì–´ 버린다. * ê°ì²´ì˜ ì¼ê´€ì ì¸ ì‚ì œì— ê´€í•´ì„œë„ ì•Œì•„ ë³´ë©´ {{{~cpp void deleteArray( ostream& logStream, BST array[]) { logStream << "Deleting array at address " << static_cast<void*>(array) << '\n'; delete [] array; } BalanceBST *balTreeArray = new BalancedBST[50]; ... deleteArray(cout, balTreeArray); // ì´ê²ƒ ì—시 ì œëŒ€ë¡œ 지워지리가 없다. }}} ìž ìœ„ì™€ ê°™ì´ ê°ì²´ì˜ ì§€ì›€ì„ ë‹´ë‹¹í•˜ëŠ” 함수를 작성했ì„때 ì—시 ë¬¸ì œê°€ 있다. {{{~cpp delete [] array }}} 는 다ìŒê³¼ ê°™ì€ ì½”ë“œë¡œ êµì²´ë˜ëŠ”ê²ƒê³¼ 같다. {{{~cpp for( int i = the number of elements in the array -1; i>0; --i) { array[i].BST::~BST(); } }}} 부모 ê°ì²´ì˜ 파괴ìžë§Œ 부르므로 ì—시 memory leak 현ìƒì„ ì¼ìœ¼í‚¨ë‹¤. == Item 4: Avoid gratuitous default constructors. == * Item 4: 암시ì 으로 ì œê³µë˜ëŠ” 기본 ìƒì„±ìžë¥¼ 피하ë¼. í˜¹ì€ ê¸°ë³¸ ìƒì„±ìžì˜ ëª¨í˜¸ì„±ì„ íŒŒì•…í•˜ë¼. C++ì—서 class templete를 만드는 중 ìƒì„±ìžë¥¼ 빼먹으면 compilerì—서 기본ì ì¸ ìƒì„±ìžë¥¼ 만들어 ìƒì„±í•´ 준다. ì—시, 당연히 ì´ˆê¸°í™”ì˜ ë¬¸ì œê°€ ë°œìƒí• 것ì´ë‹¤. 여기ì—서는 약간 ìžì„¸í•œ ë¶€ë¶„ì„ ì–¸ê¸‰í•œë‹¤. ì˜ˆì œì—서 ì‹œìž‘í•˜ìž {{{~cpp class EquipmentPiece { public: EquipmentPiece(int IDNumber); ... } }}} 해당 EquipmentPiece 는 기본 ìƒì„±ìžê°€ 부실(?) 하다. ì´ê±´ í¬ê²Œ '''3ê°€ì§€ì˜ ì£¼ì œ'''로 ì„¤ëª…í• ìˆ˜ 있다. * '''첫번째 ë¬¸ì œëŠ” 해당 í´ëž˜ìŠ¤ë¥¼ ì´ìš©í•˜ì—¬ ë°°ì—´ì„ ìƒì„± í• ë•Œì´ë‹¤. . ( The first is the creation of arrays )''' {{{~cpp EquipmentPiece bestPieces[10]; EquipmentPiece bestPieces = new EquipmentPiece[10]; // ë‘경우 초기화 해줄 ë°©ë„ê°€ 없어서 ì—러ì´ë‹¤. }}} ì´ê±¸ ì´ë ‡ê²Œ 풀어 ë³´ìž {{{~cpp int ID1, ID2, ID3, ... ID10; ... EquipmentPiece bestPiece[] = { EquipmentPiece(ID1), EquipmentPiece(ID2), EquipmentPiece(ID3), ..., EquipmentPiece(ID10), } }}} 하지만 ì´ëŸ´ 경우ì—는 array를 heap arrays(heapì˜ì— 사용 arrayë¼ëŠ” ì˜ë¯¸ë¡œ 받아들임)ë¡œì˜ í™•ìž¥ì´ ë¶ˆê°€ëŠ¥í•œ ê³ ì •ëœ ë°©ë²•ì´ë‹¤.[[BR]] 조금 ë” ì¼ë°˜ì ì¸ ë°©ë²•ì€ ë‹¤ìŒê³¼ ê°™ì´ pointer를 ì´ìš©í•œ ì ‘ê·¼ì„ ì œì‹œí•œë‹¤. {{{~cpp typedef EquipmentPiece* PEP; PEP bestPieces[10]; PEP *bestPieces = new PEP[10]; for ( int i = 0; i< 10; ++i) bestPiece[1] = new EquipmentPiece( ID Number ); }}} 하지만 ì´ëŸ¬í•œ ë°©ë²•ì€ í•œëˆˆì— ë´ë„ ë¬¸ì œê°€ 예ìƒëœë‹¤. 바로 '''delete'''ë¬¸ì œ [[BR]] ë‘가지를 구체ì 으로 ì´ì•¼ê¸° í•´ë³´ë©´, '''첫번째'''로 ''for'' 문시ì—서 í• ë‹¹ë˜ëŠ” ê°ì²´ì˜ 숫ìžë¥¼ ê¸°ì–µí•˜ê³ ìžˆì–´ì•¼ 한다. 잃어버리면 차후 resouce leakì´ ë°œìƒ í• ê²ƒì´ë‹¤. '''ë‘번째'''로는 pointer를 위한 공간 í• ë‹¹ìœ¼ë¡œ ì‹¤ì œ 필요한 memory 용량보다 ë” ì“´ë‹¤. [[BR]] 그럼 ë” ì›ƒê¸°ëŠ” ë°©ë²•ì„ ì œì‹œí•´ ë³´ìž. (ì´ ì±…ì„ ë³´ê³ ìžˆë…¸ë¼ë©´, ì´ë ‡ê²Œë„ 쓸수 있다란걸 보여주는거 같다.) {{{~cpp void *rawMemory = operator new[](10*sizeof(EquipmentPiece)); EquipmentPiece *bestPieces = static_cast<EquipmentPiece*>(rawMemory); for ( int i = 0; i< 10; ++i) new (bestPieces+1) EquipmentPiece ( ID Number ); // ì´ê±´ placement new ë¼ê³ 하여 Item 8 ì—서 언급한다. // ì²˜ìŒ ë³´ê³ ë†€ëžë‹¤. 어서 사기야 하면서 --;; // ì´ ì±… 주특기다. ë’¤ì— ì„¤ëª…í•˜ë‹ˆê¹Œ 그냥 넘어가 하는거 // 암튼 ì˜ë¯¸ëŠ” ì´í•´ 갈것ì´ë‹¤. }}} ì°¸ ê±°ì§€ ê°™ì€ ì§“ 잘해 놓는다. [[BR]] ì¼ë‹¨ 확보한 ì˜ì—ì„ ì§€ìš°ê¸°ëŠ” 쉽다. ì´ë ‡ê²Œ {{{~cpp delete [] rawMemory; }}} ì—시나 ì´ê²ƒë„ '''delete'''ì— ê´€í•œ ëª¨í˜¸ì„±ì„ ì œê³µí•œë‹¤. ë¬¸ì œì‹œ ë˜ëŠ” ì ì€ rawMemoryìƒì— ë°°ì¹˜ëœ EquipmentPieceì˜ '''destructor''' 호출 ìœ ë¬´ì´ë‹¤. 예ìƒëŒ€ë¡œ '''destructor'''를 ê°•ì œ 호출해 줘야 한다. 그래서 위가 아니ë¼, ì´ëŸ°ì‹ì˜ ì‚ì œê°€ ëœë‹¤. {{{~cpp for ( int i = 9; i>= 0; --i) bestPieces[i].~EquipmentPiece(); // ì–¸ì œë‚˜ ëŠë¼ëŠ” 거지만 C++ì„ ë°©ì¢…ì„ ê°€ì ¸ë‹¤ 줄수 있다. operator delete[](rawMemory); }}} ì°¸ê³ ë¡œ {{{~cpp delete [] bestPieces; // ì´ë ‡ê²Œ 지우는건 new operatorê°€ 건들지 않아서 불가능하다. }}} * '''ë‘번째 ë¬¸ì œëŠ” ë§Žì€ template class(특히 STLì—서) 들ì—게 ì•„í””ì„ ì•ˆê²¨ì¤€ë‹¤. ''' 아래와 ê°™ì€ template class 를 ì„ ì–¸í–ˆë‹¤ê³ ê°€ì •í•˜ë©´, {{{~cpp template<class T> class Array{ public: Array(int size); ... private: T *data; }; template<class T> Array<T>::Array(int size) { data = new T[size]; .... } }}} 첫번째ì—서 ì œê¸°ëœ ë¬¸ì œê°€ ì´ë²ˆì—는 template class ë‚´ë¶€ì—서 ì¼ì–´ ë‚˜ê³ ìžˆëŠ” ì…ˆì´ë‹¤. ê±°ì°¸ 암담한 결과를 초례한다. ë¬¸ì œëŠ” ì´ëŸ¬í•œ template class ê°€ ì´ì œëŠ” 아예 STLê°™ì€ library로 구축ë˜ì—ˆë‹¨ 사실. 알아서 잘 기본 ìƒì„±ìž 만들어 ì 용하시ë¼. 다른 ë°©ë„ ì—†ë‹¤. DeleteMe ì´ ë¶€ë¶„ì´ ë¶€ì‹¤í•˜ë‹¤ 차후 ë³´ê°• í•„ìš” * '''세번째(마지막) ë¬¸ì œëŠ” virtual base class와 ê°™ì´ ê¸°ë³¸ ìƒì„±ìžë¥¼ ê°€ì ¸ì•¼ 하나 ë§ì•„야 하나 미묘한 ë”œë ˆë§ˆì˜ ì—°ì¶œì´ë‹¤.''' ìƒê°í•´ ë³´ë¼ Virtual base classê°€ 왜 기본 ìƒì„±ìžë¥¼ 필요로 하는가. ìƒì„±ìžë¥¼ 만들어 놓으면 ìƒì†í•˜ëŠ” ì´í›„ ëª¨ë“ í´ëž˜ìŠ¤ë“¤ì—게 로드가 걸리는 ì…ˆì´ ëœë‹¤. ê·¼ì›ì´ í”ë“¤ë ¤ 모ë‘ê°€ ì˜í–¥ì„ 받는 사태ì´ë‹¤. 만약? ìˆ˜ë§Œê°œì˜ ê°ì²´ ìƒì„±ì´ë¼ë©´ ì´ê±´ 굉장한 ë¬¸ì œê°€ ë 수 있다. ---- ["MoreEffectiveC++"]