home *** CD-ROM | disk | FTP | other *** search
- Microsoft Foundation Classes Microsoft Corporation
- Technical Notes
-
- #16 : MFC and Multiple Inheritance
-
- This note describes how to use Multiple Inheritance (MI) with
- the Microsoft Foundation Classes.
-
- =============================================================================
- Why Multiple Inheritance ?
- ==========================
-
- There is an ongoing debate in the C++ and object oriented communities
- over the value of multiple inheritance (MI). The C7 compiler
- and development environment fully supports MI.
-
- The MFC class library has been designed so that you do not need to
- understand MI to use it. MI is not used in any of the MFC classes.
- We have found that MI is not required to write a class library,
- nor is it required for writing serious applications.
- The use of MI or not can be a personal decision, so we leave that
- decision to you.
-
- So you want to use MI?
- ======================
- If you already understand how to use MI, understand
- the performance trade-offs, and want to use MFC,
- this technote will tell you what you must do.
- Some of the restrictions are general C++ restrictions,
- others are imposed by the MFC architecture.
-
- There is one MFC sample that uses MI. The MINSVRMI example
- (in \c700\mfc\samples\minsvrMI) is a minimal OLE server that
- is implemented with one class. The non-MI version is called
- MINSVR (in \c700\mfc\samples\minsvr) and is implemented
- with 5 classes.
-
- This is perhaps an excessive example of using MI (5 base classes),
- but it illustrates the points made here.
-
- =============================================================================
- CObject - the root of all classes
- =================================
-
- As you know, all significant classes derive directly or indirectly
- from CObject. CObject does not have any member data, but does
- have some default functionality.
-
- When using MI, it will be common to inherit from two or more
- CObject derived classes, for example a CFrameWnd and a CObList:
-
- class CListWnd : public CFrameWnd, public CObList
- {
- ...
- };
- CListWnd myListWnd;
-
- In this case CObject is included twice, which leads to two problems:
- 1) any reference to CObject member functions must be disambiguated.
-
- myListWnd.Dump(afxDump);
- // compile time error, CFrameWnd::Dump or CObList::Dump ?
-
- 2) static member functions, including 'operator new' and 'operator delete'
- must also be disambiguated.
-
- Recommended steps:
- ------------------
- When creating a new class with two or more CObject derived base classes,
- re-implement those CObject member that you expect people to use.
-
- Operators 'new' and 'delete' are mandatory, Dump is recommended.
-
- class CListWnd : public CFrameWnd, public CObList
- {
- public:
- void* operator new(size_t nSize)
- { return CFrameWnd::operator new(nSize); }
- void operator delete(void* p)
- { CFrameWnd::operator delete(p); }
-
- void Dump(CDumpContent& dc)
- { CFrameWnd::Dump(dc);
- CObList::Dump(dc); }
- ...
- };
-
- Virtual inheritance of CObject ?
- ---------------------------------
- You may ask, "why not inherit CObject virtually, won't all of
- the ambiguity problems go away ?".
-
- Well first of all, even in the efficient Microsoft Object Model,
- virtual inheritance is not as efficient as non-virtual inheritance
- (just as Multiple inheritance is not as efficient as single
- inheritance in certain cases.) Since there is no member data in
- CObject, virtual inheritance is not needed to prevent multiple
- copies of a base class's member data.
-
- The real answer is no, virtual inheritance will not solve
- all the ambiguity problems illustrated above.
- For example: the Dump virtual member function is still
- ambiguous (since CFrameWnd and CObList implement it
- differently).
-
- Therefore we recommend following the steps above to provide
- disambiguation where you think it is important.
-
- =============================================================================
- CObject - IsKindOf and runtime typing
- =====================================
-
- The runtime typing mechanism supported by MFC in CObject uses
- the macros DECLARE_DYNAMIC, IMPLEMENT_DYNAMIC, DECLARE_SERIAL
- and IMPLEMENT_SERIAL.
- The resulting programmer feature is the ability to do a runtime
- type check to allow for safe cast-downs.
-
- These macros only support a single base class, and will work
- in a limited way for multiply inherited classes.
- The base class you specify in IMPLEMENT_DYNAMIC or IMPLEMENT_SERIAL
- should be the first (or "left-most") base class. For our example:
-
- class CListWnd : public CFrameWnd, public CObList
- {
- DECLARE_DYNAMIC(CListWnd)
- ...
- };
-
- IMPLEMENT_DYNAMIC(CListWnd, CFrameWnd)
-
- This will allow you to do type checking for the "left-most" base class
- only. The runtime type system will know nothing about additional
- bases (CObList in this case).
-
- =============================================================================
- CWnd - and message maps
- =======================
-
- In order for the MFC message map system to work correctly, there are
- two additional requirements:
-
- 1) there must be only one CWnd derived base class
- 2) that CWnd derived base class must be the first (or "left-most")
- base class.
-
- In the example above, we have made sure that 'CFrameWnd' is the
- first base class.
-
- Some counter examples:
- class CTwoWindows : public CFrameWnd, public CEdit
- { ... };
- // error : two copies of CWnd
-
- class CListEdit : public CObList, public CEdit
- { ... };
- // error : CEdit (derived from CWnd) must be first
-
- =============================================================================
-