|
|
1.1 ! root 1: Microsoft Foundation Classes Microsoft Corporation ! 2: Technical Notes ! 3: ! 4: #16 : MFC and Multiple Inheritance ! 5: ! 6: This note describes how to use Multiple Inheritance (MI) with ! 7: the Microsoft Foundation Classes. ! 8: ! 9: ============================================================================= ! 10: Why Multiple Inheritance ? ! 11: ========================== ! 12: ! 13: There is an ongoing debate in the C++ and object oriented communities ! 14: over the value of multiple inheritance (MI). The C7 compiler ! 15: and development environment fully supports MI. ! 16: ! 17: The MFC class library has been designed so that you do not need to ! 18: understand MI to use it. MI is not used in any of the MFC classes. ! 19: We have found that MI is not required to write a class library, ! 20: nor is it required for writing serious applications. ! 21: The use of MI or not can be a personal decision, so we leave that ! 22: decision to you. ! 23: ! 24: So you want to use MI? ! 25: ====================== ! 26: If you already understand how to use MI, understand ! 27: the performance trade-offs, and want to use MFC, ! 28: this technote will tell you what you must do. ! 29: Some of the restrictions are general C++ restrictions, ! 30: others are imposed by the MFC architecture. ! 31: ! 32: There is one MFC sample that uses MI. The MINSVRMI example ! 33: (in \c700\mfc\samples\minsvrMI) is a minimal OLE server that ! 34: is implemented with one class. The non-MI version is called ! 35: MINSVR (in \c700\mfc\samples\minsvr) and is implemented ! 36: with 5 classes. ! 37: ! 38: This is perhaps an excessive example of using MI (5 base classes), ! 39: but it illustrates the points made here. ! 40: ! 41: ============================================================================= ! 42: CObject - the root of all classes ! 43: ================================= ! 44: ! 45: As you know, all significant classes derive directly or indirectly ! 46: from CObject. CObject does not have any member data, but does ! 47: have some default functionality. ! 48: ! 49: When using MI, it will be common to inherit from two or more ! 50: CObject derived classes, for example a CFrameWnd and a CObList: ! 51: ! 52: class CListWnd : public CFrameWnd, public CObList ! 53: { ! 54: ... ! 55: }; ! 56: CListWnd myListWnd; ! 57: ! 58: In this case CObject is included twice, which leads to two problems: ! 59: 1) any reference to CObject member functions must be disambiguated. ! 60: ! 61: myListWnd.Dump(afxDump); ! 62: // compile time error, CFrameWnd::Dump or CObList::Dump ? ! 63: ! 64: 2) static member functions, including 'operator new' and 'operator delete' ! 65: must also be disambiguated. ! 66: ! 67: Recommended steps: ! 68: ------------------ ! 69: When creating a new class with two or more CObject derived base classes, ! 70: re-implement those CObject member that you expect people to use. ! 71: ! 72: Operators 'new' and 'delete' are mandatory, Dump is recommended. ! 73: ! 74: class CListWnd : public CFrameWnd, public CObList ! 75: { ! 76: public: ! 77: void* operator new(size_t nSize) ! 78: { return CFrameWnd::operator new(nSize); } ! 79: void operator delete(void* p) ! 80: { CFrameWnd::operator delete(p); } ! 81: ! 82: void Dump(CDumpContent& dc) ! 83: { CFrameWnd::Dump(dc); ! 84: CObList::Dump(dc); } ! 85: ... ! 86: }; ! 87: ! 88: Virtual inheritance of CObject ? ! 89: --------------------------------- ! 90: You may ask, "why not inherit CObject virtually, won't all of ! 91: the ambiguity problems go away ?". ! 92: ! 93: Well first of all, even in the efficient Microsoft Object Model, ! 94: virtual inheritance is not as efficient as non-virtual inheritance ! 95: (just as Multiple inheritance is not as efficient as single ! 96: inheritance in certain cases.) Since there is no member data in ! 97: CObject, virtual inheritance is not needed to prevent multiple ! 98: copies of a base class's member data. ! 99: ! 100: The real answer is no, virtual inheritance will not solve ! 101: all the ambiguity problems illustrated above. ! 102: For example: the Dump virtual member function is still ! 103: ambiguous (since CFrameWnd and CObList implement it ! 104: differently). ! 105: ! 106: Therefore we recommend following the steps above to provide ! 107: disambiguation where you think it is important. ! 108: ! 109: ============================================================================= ! 110: CObject - IsKindOf and runtime typing ! 111: ===================================== ! 112: ! 113: The runtime typing mechanism supported by MFC in CObject uses ! 114: the macros DECLARE_DYNAMIC, IMPLEMENT_DYNAMIC, DECLARE_SERIAL ! 115: and IMPLEMENT_SERIAL. ! 116: The resulting programmer feature is the ability to do a runtime ! 117: type check to allow for safe cast-downs. ! 118: ! 119: These macros only support a single base class, and will work ! 120: in a limited way for multiply inherited classes. ! 121: The base class you specify in IMPLEMENT_DYNAMIC or IMPLEMENT_SERIAL ! 122: should be the first (or "left-most") base class. For our example: ! 123: ! 124: class CListWnd : public CFrameWnd, public CObList ! 125: { ! 126: DECLARE_DYNAMIC(CListWnd) ! 127: ... ! 128: }; ! 129: ! 130: IMPLEMENT_DYNAMIC(CListWnd, CFrameWnd) ! 131: ! 132: This will allow you to do type checking for the "left-most" base class ! 133: only. The runtime type system will know nothing about additional ! 134: bases (CObList in this case). ! 135: ! 136: ============================================================================= ! 137: CWnd - and message maps ! 138: ======================= ! 139: ! 140: In order for the MFC message map system to work correctly, there are ! 141: two additional requirements: ! 142: ! 143: 1) there must be only one CWnd derived base class ! 144: 2) that CWnd derived base class must be the first (or "left-most") ! 145: base class. ! 146: ! 147: In the example above, we have made sure that 'CFrameWnd' is the ! 148: first base class. ! 149: ! 150: Some counter examples: ! 151: class CTwoWindows : public CFrameWnd, public CEdit ! 152: { ... }; ! 153: // error : two copies of CWnd ! 154: ! 155: class CListEdit : public CObList, public CEdit ! 156: { ... }; ! 157: // error : CEdit (derived from CWnd) must be first ! 158: ! 159: =============================================================================
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.