Dynamic creation is the object of the specified class created at runtime, which is widely used in MFC. For example, frame window objects, visual objects, and document objects must be dynamically created by document template objects. I think this is a question that every MFC learner wants to understand.
When I first came into contact with MFC, it was easy to be confused. We don't need to design the various types of MFC, but the biggest concern is that we don't need to instantiate objects. The most intuitive understanding is that when we need a framework, we should write the CFrameWnd myFrame by hand; when we need to view the frame, we should add the CView myView in person ;......
However, MFC does not give us this opportunity, which leads to the pop-up if the window is not instantiated! It's as incredible as you can watch a TV with a circuit diagram. If you think about it, you may think it is simple. However, MFC will automatically help us complete the code of the CView myView stream !!! In fact, when writing an MFC program, we almost need to derive and rewrite each category. In other words, MFC does not know how we plan to rewrite these classes, and of course we do not plan to create these classes for all "static. It is useless even if you create these classes statically, because we never directly use the instances of these classes to do anything. We only know that what we want to do is to plug into various categories. No matter what variables and methods are, after the plug-in is complete, we seem to be not instantiating the object, and the program can run!
In order to hand over your classes to MFC, MFC uses the same method to accurately create different classes. What should we do? Similarly, we need to create a linked list, record all kinds of key information, and find this information during dynamic creation, just like the RTTI in the previous section! We can design a class:
Struct CRuntimeClass {
LPCSTR m_lpszClassName; // Class Name Pointer
CObject * (PASCAL * m_pfnCreateObject) (); // pointer to the function used to create an object
CRuntimeClass * m_pBaseClass; // introduced during RTTI
CRuntimeClass * m_pNextClass; // point to the next element of the linked list. (many friends didn't use this pointer when talking about RTTI in the previous section. I thought it was better to understand it because I didn't have this pointer, this linked list cannot be connected, while m_pBaseClass is only directed to the base class. m_pBaseClass cannot be traversed in the tree hierarchy of MFC)
CObject * CreateObject (); // create an object
Static CRuntimeClass * PASCAL Load (); // traverses the entire type linked list and returns the dynamically created object.
Static CRuntimeClass * pFirstClass; // header pointer of the type linked list
};
You may feel dizzy when so many things are inserted into the structure. As for CObject * (PASCAL * m_pfnCreateObject) ();, this method defines function pointers, which may be a bit unfamiliar. Function pointers are generally used as optional chapters in C ++ books, but such functions are often used in MFC, such as Callback functions we are familiar. Simply put, m_pfnCreateObject stores the address of a function and creates an object. In other words, when m_pfnCreateObject points to different functions, we will create different types of objects.
If there is a function pointer, we need to implement a function that is the same as the original defined parameter and return value. In MFC, it is defined:
Static CObject * PASCAL CreateObject () {return new XXX}; // XXX indicates the class name. If the class name is different, we create different objects.
Therefore, we can construct CRuntimeClass to the linked list as follows:
CRuntimeClass classXXX = {
Class Name,
......,
XXX: CreateObject (), // m_pfnCreateObject refers to the Function
RUNTIME_CLASS (base class name) // The RUNTIME_CLASS macro returns the CRuntimeClass object pointer.
NULL // m_pNextClass is empty for the moment. At last, we try to point it to the header of the old linked list.
};
In this way, we can use the function pointer m_pfnCreateObject (pointing to the CreateObject function) to create a new object at any time. We also noticed that when designing a CRuntimeClass class pair, only the class name (and the base class name) are different (we replaced it with XXX). The rest is the same, this is exactly what we want, because two macros are also used in dynamic creation like RTTI. As long as the class name and base class are passed as macro parameters, the conditions can be met.
That is to say, we use the DECLARE_DYNCREATE (CLASSNMAE) macro in the class description and the IMPLEMENT_DYNCREATE (CLASSNAME, BASECLASS) macro in the class implementation file to add a linked list for us, as for how these two macros create a linked list for us, we can play the text substitution game on our own, which is not cumbersome here. However, it should be noted that the dynamic creation macro xxx_DYNCREATE contains the RTTI macro, that is, xxx_DYNCREATE is the "enhanced version" of xxx_DYNAMIC ".
At this point, it is necessary to understand that the m_pNextClass pointer is not described in the previous lesson. Because the hierarchical structure of MFC is tree-like, it is not a straight line. If we only have one m_pBaseClass pointer, it will only follow the base class and will miss other branches. During dynamic creation, you must check the entire linked list to see how many objects to be dynamically created, that is, the object to be created from the header (pFirstClass) start to traverse until the end of the table (m_pNextClass = NULL). A CRuntimeClass object cannot be missed.
So whenever a new linked list element is added to the linked list, we need to make the new linked list element a header, and m_pNextClass points to the header of the original linked list, that is, as shown in the following figure (of course, we don't need to worry about these, but the RTTI macro helped us do it ):
PNewClass-> m_pNextClass = CRuntimeClass: pFirstClass; // The m_pNextClass pointer of the new element points to the header of the linked list to be added.
CRuntimeClass: pFirstClass = pNewClass; // The head pointer of the linked list points to the newly inserted element.
Now, with the linked list above, we can analyze the dynamic creation.
With a linked list with a class name, function pointer, and dynamic function creation, we can know the steps to dynamically create a function:
1. Obtain the name of A class to be dynamically created (assumed as ).
2. Compare the m_lpszClassName pointing to the class name of each element in A and the linked list.
3. If the same class name as AIS found, the pointer to the CRuntimeClass element of A is returned.
4. Determine whether m_pfnCreateObject points to the creation function. If yes, create an object and return the object.
The Code is as follows (the following two functions are CRuntimeClass functions ):
//// // The following is the CRuntimeClass object to which the table is located from the header to the end of the table based on the class name ////////// //
CRuntimeClass * PASCAL CRuntimeClass: Load ()
{
Char szClassXXX [64];
CRuntimeClass * pClass;
Cin> szClassXXX; // assume this is the name of the class we want to dynamically create.
For (pClass = pFirstClass; pClass! = NULL; pClass = pClass-> m_pNextClass)
{
If (strcmp (szClassXXX, pClass-> m_lpszClassName) = 0)
Return pClass;
}
Return NULL
}
/// // Create an object based on CRuntimeClass ///////////
CObject * CRuntimeClass: CreateObject ()
{
If (m_pfnCreateObject = NULL) return NULL;
CObject * pObject;
PObject = (* m_pfnCreateObject) (); // function pointer call
Return pObject;
}
With the above two functions, we can dynamically create objects by calling them during program execution.
We can also implement dynamic creation in a simpler way. We noticed that there is a RUNTIME_CLASS (class_name) macro in our program class, which is defined in MFC:
RUNTIME_CLASS (class_name) (CRuntimeClass *) (& class_name: class # class_name ))
The function is to get the RunTime information of the class, that is, to return the CRuntimeClass object to which the class_name belongs. In the CSingleDocTemplate function under the InitInstance () function of our application programmer class (CMyWinApp), there are:
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CMyView)
This macro is used to obtain the document, framework, and view RunTime information when constructing a document template. With RunTime information, we can dynamically create one statement, for example:
ClassMyView-> CreateObject (); // The object is called directly using the CreateObject () of CRuntimeClass ()
Now, careful friends can understand the steps required for dynamic creation:
1. Define a constructor without parameters (default constructor). Because we use CreateObject () for dynamic creation, only one statement is return new XXX without any parameters. Therefore, we need a non-argument constructor.
2. DECLARE_DYNCREATE (CLASSNMAE) macro is used in the class description, and IMPLEMENT_DYNCREATE (CLASSNAME, BASECLASS) macro is used in the class implementation file. This macro constructs the CRuntimeClass object, and add it to the linked list.
3. Use the macro RUNTIME_CLASS to obtain the RunTime information of the class, and then use the CRuntimeClass member function CreateObject to create an instance of the class.
4. CObject * pObject = pRuntimeClass-> CreateObject (); // complete dynamic creation.