Export class Design
The previous blog details the various knowledge points (http://blog.csdn.net/z702143700/article/details/45989993) of the development of the class library, this article will further state the problem of the development norm of the export class in the course of class library development.
The DLL developed by C + + was originally designed as a function-level shared library and does not really provide the information necessary for a class. Program reuse on the class layer is only possible with Java and C # generated class files. So, when we use C + + development class library often encounter class design problems, design is not good, will appear dll hell.
DLL Hell
When the DLL for the exported class is maintained and modified, adding member variables, modifying the base class of the exported class, and so on can lead to unintended consequences, and perhaps the application will no longer work after the user has updated the latest version of the DLL library. That is the famous DLL Hell (DLL Hell) problem.
DLL The generation of Hell problems
- The application accesses the public variables of the class directly, and the public variable is defined in the new DLL;
- The application calls a virtual function of the class, and in the new class, a virtual function is added to the front of the virtual function;
- The base class of the new class has been modified, and the size of the base class has changed;
- After the new class, the member variables are added, and the member functions of the new class will access and modify the variables;
As an example:
Suppose the DLL has an export class Classtool:
class ClassTool { public: intGetVar(); private: int m_var1; }; int ClassTool::GetVar() { return m_var1;}
The application uses this class:
ClassTool ct;printf(“%d”, ct.GetVar());
The need to add a variable to a class because of a change in demand:
//修改后的类{ public: intGetVar(); private: int m_var2; int m_var1; };
After the updated DLL compilation connection is completed and copied to the application directory, the unlucky application will not be able to get the correct value again after calling the GetVar method. Such a thing, called it a Hell (Hell).
Analysis:
First, the program statement "Classtool CT;" Applies a piece of memory for this class. This memory holds all the member variables of the class, as well as the virtual function table. The size of the memory is determined by the declaration of the class, which is determined when the application is compiled.
Then, when called "D.getvar ()", the application of this piece of memory as the this pointer to the GetVar function, the GetVar function from the location of this point, plus the m_var1 should be offset, calculate the location of the memory m_var1, and from that location to take the data back. The offset of the m_var1 relative to this is determined by the position defined by M_VAR1 in the class, and the former member variable is also more forward in memory. This offset is determined when the DLL is compiled.
When the definition of Classtool changed to a modified state, something changed.
The first variable is the size of the memory. Because the modified Classtool has one more member variable, the memory becomes larger. However, this application is not known.
The second variable is the offset address of the M_VAR1. Because the implementation offset address of a M_VAR2,M_VAR1 is defined before M_var1 is actually back. So d. GetVar () will be accessing the location behind the original M_VAR1, which is beyond the back of the original block of memory.
Obviously, after the DLL has been replaced, the application has applied for a piece of memory at its original size, and the method it calls accesses a larger area than the memory, and the error is unavoidable.
always say that, accidentally, your program will fall into hell. By analyzing these error-causing situations, it is found that only three changes can cause errors, because these three points are what the application using this DLL needs to determine at compile time, namely:
1) the size of the class ;
2) The offset address of the class member ;
3) The order of virtual functions .
Export Class Design Specification
The following default specifications should be followed in the Export class design:
1. do not generate instances of the class directly . For the size of a class, when we define an instance of a class, or use the new statement to generate an instance, the size of the memory is determined at compile time. To make an application independent of the size of a class, there is only one way: The application does not generate an instance of the class, which is generated using a function in the DLL. The constructor for the exported class is defined as Private (privated), and a static (static) member function (such as newinstance ()) is provided in the export class to generate an instance of the class. Because the newinstance () function is recompiled in the new DLL, it always returns the correct size of the instance memory. You can also use a global function to return an instance of a class (as in the example in my previous blog).
2. do not directly access member variables . The offset address of the variable is used when the application accesses the member variable of the class directly. So the way to avoid offset address dependencies is not to directly access member variables. The access control for all member variables is defined as a level above the protected type (protected), and a Get or set method is defined for the member variable that needs to be accessed. The Get or set methods are recompiled when the new DLL is compiled, so you always have access to the correct variable location.
3. try not to use virtual functions . Even if you have one, don't let the app access it directly. Because the class's constructor is already private (privated), the application does not inherit the class, nor does it implement its own polymorphism. If there are virtual functions in the parent class of the exported class, or if the design requires (such as a framework such as class Factory mode), be sure to declare these functions as protected (protected) levels and redesign the member functions that call the consideration function for the application. This is similar to the handling of member variables.
If the exported class can follow the above three points, later upgrades to the DLL will be considered safe.
In addition, if you are maintaining a DLL for an existing export class, you should also be aware that you should not change all of the member variables, including the parent class of the exported class, regardless of the order or quantity of the definition, and do not move all virtual functions, either in order or in quantity.
When exporting a class design, remember not to export anything other than a function.
It is recommended that when you publish the DLL of the exported class, you redefine the declaration of a class, which can be listed in the declaration of the class, regardless of the member variables in the original class, as in the following example:
class ClassInterface { privated: ClassInterface(); public: staticNewInstance(); int GetVar(); void SetVar(); void Function(); };
In the application, use ClassInterface as the header file for the class, which avoids any security problems that might result.
Principles of export class design for C + + class library development