Introduction: the online criticism of MFC is endless. It is not good to say that it is similar to MFC. Some netizens even use "bad" to describe MFC. I have been learning mf c for some time. I feel that my level of MFC is moderate, and there is still a gap between my skills in using it. I have a deep understanding of the "pain" of learning MFC, so I usually try to avoid using MFC at work. A few days ago, I saw a discussion about the design patterns used in MFC in csdn. I thought this was a very meaningful discussion. Why can't we analyze and learn MFC from the perspective of implementers? As a huge application framework, MFC contains a lot of excellent design ideas and methods, if these excellent design ideas and methods can be flexibly applied to our own code, our design and code quality can go up to another level, and we can also go up to another level. To analyze the design patterns used in MFC, it is clear that these two aspects are very familiar. Both the design model and MFC are a very huge system. Any learning process is a long and painful process. Therefore, I think it is almost impossible to make a comprehensive analysis (except for the cool people ), therefore, the analysis here is only limited to my own limited knowledge, but I believe that with the in-depth study and the improvement of my own level, the analysis will become more comprehensive.
Factory, as its name implies, is something to make things. Specifically, software development refers to the "things" used to generate objects ". Here, "things" may be a method (such as a global function) or a class (the class factory in COM ). To put it simply, the purpose of applying the factory is to hide the specific object creation process. The customer Code provides the materials required to create the object, and then obtains the created object from the factory, you don't have to worry about how objects are created. Although the factory idea is simple and simple, we almost ignore its existence, but it frequently appears in the Code and becomes the most frequently used design idea.
The simplest Factory is a function, which creates only one object. For example, the following code:
Class football;
Football * createfootball ();
From the function name createfootball, we can see that this function is used to create a football object. Of course, we can add some parameters to the function to specify the attributes of the created object. This function (or similar function) has a fatal problem, that is, the function is too single and rigid. If we have n kinds of objects, we need to write n corresponding functions to create them. Is there a better way?
(We finally came to the stage of the MFC and applaud it !)
(MFC: Today is very exciting! Thank you, Microsoft. Thank you, oo. Thank you for your interest in me ...)
Only one method can be used to create all the objects derived from cobject. This method is cruntimeclass: Createobject (). What does MFC do to make cruntimeclass: Createobject () so amazing? The secret here is the cruntimeclass class (more specifically, cruntimeclass is a struct ). When constructing an object, we first need to know the memory space occupied by the object, and also need a constructor to initialize the constructed object. In cruntimeclass, there are two member variables involved in these two aspects:
M_nobjectsize-the size of the object, in bytes
Based on its value, the objects are allocated with less space when they are created.
M_pfncreateobject-a function pointer to the default constructor that creates an object of your class
This is a function pointer pointing to the default constructor of an object. You can call the default constructor to initialize an object when creating an object.
The next problem to be solved is how to associate cruntimeclass with the object I want to create, that is, let cruntimeclass know what to create. Here, MFC uses two macros (declare_dyncreate/implement_dyncreate) to establish this connection. Through these two macros, any class derived from cobject will have a corresponding cruntimeclass object, which stores some information about the object to be created, such as the size of the object mentioned above, constructor pointer and so on.
The next question is how to get the cruntimeclass object at runtime, and then use it to create the object I need. Here we need to use the support of runtime type recognition (rtti) in MFC. MFC uses the declare_dynamic/implement_dynamic macro to implement rtti. Simply put, each cruntimeclass object (static object) corresponding to each class will be added to a static, global cruntimeclass linked list. Later, you can find this linked list, you can find the cruntimeclass object of each class object.
For cruntimeclass: Createobject (), each object corresponds to a factory function, but we do not need to manually add these factory functions. MFC is implemented in a more clever way. Cruntimeclass also provides a static function: static cobject * Pascal Createobject (lpcstr lpszclassname). This function can create corresponding objects only by class name, actually, a function is used to create N types of objects (a bit like a machine Cat's treasure chest :)). The implementation mechanism is the same as above, so I will not talk about it here.
I just analyzed the dynamic creation of objects in MFC in principle. The specific implementation details are hidden behind the mysterious macro. If you are interested in the implementation details, you can expand the macro and analyze it, or read other books.
Through the above analysis of object dynamic creation in MFC, if we want a function to be able to create multiple objects, the function prototype generally has the following features:
1. Function return value. The return values of factory functions are generally base class pointers. You need to convert the pointer to the correct type pointer before using this pointer. For example, the following code:
Class cshape {...};
Class crectange: Public cshape {...};
Cshape * createrectange (){
Return new crectange ();
}
Crectange * prect = static_cast <crectange *> (createrectange (); // explicitly Casting
It can be seen that this requires all classes to be derived from a base class, just as almost all classes in MFC have a common base class cobject.
2. There are no special requirements for function parameters. Function parameters can be used to differentiate the object type to be created, for example, the following code:
Class cshape {...};
Class crectange: Public cshape {...};
Class ccircle: Public cshape {...};
Cshape * createshape (Enum shapetype ){
If (shapetype = rectange) return New crectange ();
If (shapetype = circle) return New ccircle ();
}
In MFC, there is also an example of coleobjectfactory. According to the class name, we can guess that the coleobjectfactory is a class factory used to create OLE objects. Constructor of coleobjectfactory:
Coleobjectfactory (refclsid CLSID, cruntimeclass * pruntimeclass, bool bmultiinstance, lpctstr lpszprogid );
The first two parameters determine the type of the object to be created.
Then, the created object is returned by calling coleobjectfactory: oncreateobject.
References:
1. msdn
2. "different ways of implementing factories"-http://www.codeproject.com/cpp/all_kinds_of_factories.asp
3. "Object creation: Implementing factory patterns in C ++"-http://www.raba.com /~ Jcstaff/oodev/presents/objcreat/