In the process of developing back-office services, we often need to fetch data from the database and cache the data locally, and our service also needs to have the ability to update the data: both scheduled proactive updates and passive updates that the service receives notifications when database data is updated.
Before the need to use the above functions, imitate the group of common data cache part of the code to write, it is very convenient, basically only need to write their own two classes: one is to fetch data and cache the data of the class Xxxdata, a fan out of the data class Xxxfetcher.
When you need to use the data, pass:
FetcherFactory::getFetcher<XXXFetcher>()
You can get a pointer to a Xxxfetcher object.
View FetcherFactory.h's Notes:
/** * 配置中心, 存储各种配置, 会自动搜索项目中的Fetcher实现类, 加载, 并 * 在收到刷新配置的通知时调用update方法 * 需要在服务器启动的onInitialize中调用本类的Initialize方法进行初始化 */
Important: The Fetcher implementation class in the project is automatically searched and loaded.
That is, fetcherfactory can automatically find the Fetcher implementation class in the project and then dynamically create the Xxxfethcer object.
What do you call dynamic creation?
is the ability to dynamically create an object of that class based on the name of a class.
For example, your program needs to use a text file, and this file contains some class names, can you dynamically generate these classes according to these names?
/*****************************************************************************//* The name of the class read from the file is stored in the string variable szclassname and now assumes that the read-out string is *//* "CString", and class CString derived from CObject, then we can point to the derived class with the base class pointer *//***********************************/*****************************************/char szclassname[20]cobject *pob;pob = new Szclassname; /* Concept version */
Of course, these are just a conceptual version, because C + + does not support dynamic creation of objects based on the class name. In C + +, operator new follows only the name of the data structure and cannot be followed by a string.
So, what is the way to achieve the "dynamically generated class object by name" Purpose?
The simplest and most brutal approach is to use nested If...else ... Statement, and repeatedly compares the read-out class name to the expected one, and then generates an object of this class. Indeed, this is one of the solutions, but if the program is going to use a lot of classes, and often change or add, would it be often to rewrite the function of recognizing strings? In that case, it will be cumbersome and error-prone.
So how is "dynamic Creation" in the group code implemented?
First look at the Fetcher class notes:
/** * 自动加载的逻辑类, 会在FetcherFactory::Initialize中被自动加载, 在FetcherFactory::update时循环调用所有Fetcher::update方法 * 其实现类必须满足下述条件: * 1. 继承自本类 * 2. 以Fetcher为类名结尾, 例如XXXFetcher, YYYFetcher * 3. 在.h和.cpp文件中分别添加DECLARE_FETCHERHOLDER_DYNCREATE和IMPLEMENT_FETCHERHOLDER_DYNCREATE宏 * 4. 项目中不能有任何TC_DYN_Object子类同名 * * 模拟MFC,动态生成类 */
It seems to be the first to learn how MFC dynamically generates class objects.
Below we simply simulate the implementation of the MFC method.
Basic knowledge:
class CExample{private:int x;public:int y;staticlong/*其它数据和函数*/};CExample j1,j2;
J1,j2 two objects share a variable z, that is, if a member variable is called static, then no matter how many objects the class defines, this member variable always has only one copy in memory. In fact, the variable z actually exists in memory before the class cexample has not defined any objects. We can use this feature to realize the dynamic recognition and generation of classes.
In MFC, there is a special class CRuntimeClass, which is the most critical place to achieve the above functions.
CRuntimeClass's statement:
class CObject; /* Declaration CObject is a class that will be defined later */ struct Cruntimeclass{char *m_lpszclassname; /* Store class name */ int m_nobjectsize; /* hold Object size */ cobject* (*m_pfncreateobject) (); /* pointer to the function that returns a CObject */ Cruntimeclass* M_pnextclass; /* type of pointer */ static Cruntimeclass* Pfirstclass; /* static variable, linked list header */ static cobject* CreateObject (const char * lpszClassName); /* Create object based on class name */};
The next thing to do is that each class (which we want to generate an object based on the class name) has a static CRuntimeClass member variable (so each class has only one copy), and the variable has a certain naming convention, such as the classxxx in the example below. These variables are then strung through a linked list, which can then be obtained by CRuntimeClass::p FirstClass.
For the convenience of programming later (and also for privacy), we define two macros:
/* 声明 */#define DECLARE_DYNAMIC(class_name)\public://定义CRuntimeClass成员变量staticclass##class_name;//获取CRuntimeClass变量的接口virtualconst;
/ * Implementation * /#define IMPLEMENT_DYNAMIC (class_name) \//Global string, which holds the class name of this classChar_lpsz# #class_name []= #class_name;//new An object of this class, a non-member functioncobject* Create# #class_name () \{return Newclass_name; }//Initialize the CRuntimeClass static member variable, passing in the name of the class and the address of the CREATE function aboveCRuntimeClass class_name::class# #class_name ={\_lpsz# #class_name, sizeof (class_name), create# #class_name};\//Defines an object of type Class_init, using the address construction of the CRuntimeClass member variableStaticClass_init _init_# #class_name (&class_name::class# #class_name);//Returns the address of the CRuntimeClass member variablecruntimeclass* Class_name::getruntimeclass ()Const{return&class_name::class# #class_name;}
The # #告诉编译器 that appears in the macro definition, bundling two strings together.
Where class_init is defined as follows:
struct CLASS_INIT{ CLASS_INIT(CRuntimeClass* pNewClass);};
The Class_init constructor is implemented as follows:
CLASS_INIT::CLASS_INIT(CRuntimeClass* pNewClass){ pNewClass->= CRuntimeClass::pFirstClass; CRuntimeClass::pFirstClass= pNewClass;}
Thus, the CRuntimeClass member variables of each class are concatenated through the linked list, and the list header is CRuntimeClass::p FirstClass (a static member variable).
In this way, we just put the macro declare_dynamic in the definition file (. h file) of the class and put the macro implement_dynamic in the implementation file (. cpp file) of the class to achieve our goal.
As an example:
//CObject.hclass CObject{DECLARE_DYNAMIC(CObject)}//CObject.cppIMPLEMENT_DYNAMIC(CObject)
The compiler does this:
//cobject.h class cobject{< Span class= "Hljs-keyword" >public : static cruntimeclass Classcobject;virtual cruntimeclass* getruntimeclass () const ;} //cobject.cpp char _lpszcobject[]= "CObject"; cobject* Createcobject () {return new CObject;} CRuntimeClass cobject::classcobject={_lpszcobject,sizeof (class_name), Createcobject}; static Class_init _init_cobject (&cobject::classcobject); cruntimeclass* Cobject::getruntimeclass () const { return &CObject::classCObject; }
Let's say we have 3 classes of a,b,c, all of them inherit from CObject, and add two macros each, and what happens when we compile the code?
- Create a static variable Pfirstclass for the class CRuntimeClass, which is the head pointer of the linked list;
- Create a static variable of type CRuntimeClass for Class A, B and C;
- Create a static variable of type Class_init in the. cpp file for each class, and in the constructor of the variable, insert the variable of type A, B, C, CRuntimeClass, in step 2 into the head of the list.
This way, as long as we add two macros declare_dynamic and implement_dynamic to the class definition and declaration, and let all classes inherit from CObject, we can get a list, The list holds variables of type CRuntimeClass in each class, and the list header is CRuntimeClass::p firstclass.
With this list, we can traverse the entire list,
CRuntimeClass::CreateObject(lpszClassName)
method to create the corresponding object according to the class name lpszClassName ~
So we do not modify the already done code, the realization of the object of the dynamic recognition and generation purposes. Later, as long as all the classes derive from the class CObject and add two macros accordingly, they have the ability to recognize and generate dynamically.
(The above code is relatively brief, not necessarily very accurate, is intended to intuitively understand, feel the realization of this principle.) )
Through learning, we have roughly learned how to use C + + to dynamically generate class object functions. In the next article, I will analyze the data cache and the related functional code of the update at the beginning of this article.
C + + implementation dynamically generates class objects based on class name