Semantic needs

zhaozj2021-02-12  147

I have seen a lot of poor design, and many programmers are only realized for the final function, and they write a balanced code, and there is almost no semantics, and I think this is a programmer's cultivation problem. For a programmer, it has far-reaching meaning. Semantics is the meaning of language, in computer programming, the interpretation of memory operation and machine directives. It shows the clearness of the program writer logical thinking, not only in computer programming, but also in society, that is, the so-called embassy is clear. As far as the system designer's point of view, semantic indicates the meaning of each interface, which guides the designer how to design the interface function's parameter type and the name of the interface function (ie, the meaning of the management person, indicating that the following functional departments The necessity, the responsibilities of each function, how to develop it. However, this article only discusses the meaning of the latest write code in the computer programming in computer programming, which cannot be ignored. Code debugging with good semantics is easy, high stability, good readability. Only the semantics and use provided by the C language are discussed here.

Types of

C provides a variety of basic variable types such as CHAR, INT, long, which already provides semantic -unsigned long indicates that the number in this variable is considered to be an unsigned long-term number. "It is considered to be" and "Yes" is a serious difference. Any type of variable is "Yes", and the type of variable has been included in the case of the size of the memory space, which is also included, indicating that it should be "considered" some meaning by code reading readers and code writers. Not a number. This is just as we will say a byte array is a bitmap rather than an array. The use of types is widely used in each library. In the Win32 API, HWND, Handle and other handles are actually just a void *; lParam, WPARAM, etc. are just a four-byte number. However, they are all given an important meaning, and hwnd represents a window handle instead of a pointer, indicating that the programmer should treat it as a pointer, but should be a cookie, a serial number, by handling it to the Win32 API. The corresponding window (even if it is actually a pointer). Of course, there are still many types definitions for convenience, such as UINT, USHORT, etc. When writing code, you should select the correct variable type. If a for (unsigned long i = 0; i

Const of modified variable

The Const keyword is used to indicate that the value of the variable it is modified cannot be modified. It should be noted that "cannot be modified", but "not used to write", and "cannot modify" is its additional effect (or implementation), and the result is called constant, this is exactly It is not used to write "" reflection. The use of macros in the C language defines the harm of constants that the macro cannot let the compiler join the semantic check row because there is no type of information. Tell the compiler using the constant, the compiler can perform a little semantic check-type match check, so the constant should be used to use const variables, and the macro should be used for code configuration (such as defined code versions, Simplified (see an inline function) like Unicode version) and code. CONST of the modified member function

When the const modifies member functions, the modified member function cannot modify the value of its corresponding class member variable. Similarly, it is not "can't modify", but "will not modify", "can't modify" is its additional effect (or implementation). I have seen some teachers' lectures and some textbooks to speak the Const member function to help programmers discover logic errors, that is, probably programmers have modified member variables in a function that cannot modify the member variables! This is the true place to fall! If a programmer has modified member variables in the Const member function, it can only indicate that the programmer's logic mess, you don't know what you have, it is not enough to qualify for programmers. They generally discovered warnings, and then remove that const, and even more, never use const this keyword modified member function. Const is already determined before writing the code. When writing the definition of the class, you can determine if this member function should be const (by the semantics of this member function). The most common is a pair of GET / SET member functions to operate a member variable, such as: inline ulong cabclist :: getCount () const {assert_valid (this); return m_count;} Bool Cabclist :: setCount (Ulong Count) { Assert_Valid (this); // More code m_count = count; return true;} The GET member function can determine if it should be a const-- class instance (one instance of class) before writing its definition. Logically does not affect the state of the class instance. However, the SET member function must not be constant - set the status of the class instance, of course affect the status of the class instance. If you look for an element in the chain table class, it is logically independent of class instance, and it will not affect its status, so it should still be constant. Determining the work of the Const member function should be done by the designer, unrelated to programmers (special referred to the code), but some simple small classes should be completed by the programmer himself, so it should still be understood in conn Semantics. Use the Const member function as mentioned in the type. There is a department class, which has multiple CabClist's variables to store personnel, finance and other information, and then it is clearly a member function of personnel. It is clear that the Const member function is called to Cabclist :: getCount. Here is very appropriate - call the Const member function in the Const member function, there is no warning. If these two classes are written by two people, they do not know each other's definition when they define classes, and everyone is written in semantics, and the last code is very appropriate. However, it is still possible that there is a case where the member variable is required to be modified in a member function that should be constant. For this, refer to the example in the mutable below. Public, Protected, Private

The class of public, protected, and private can be said to be just for semantics, there is no impact on the final code, but it is important, thus leading to object-oriented programming ideas. I have seen a lot of saying - in order to have object-oriented ideas, the member variable is private, all of which are operated by the GET / SET member function (or similar function) mentioned above. The semantics of these three keywords will be explained below, but it should be noted that the incorrectness of the previous statement - at least the CWnd :: m_hwnd in the MFC is public. Publicity indicates that its modified member function or member variable can be seen by an external (an operator of class instance, i.e., the code using the class instance). Again, not "can be seen", but "it is used." For example, open a grocery store, the facade is coming to the pedestrian, not the facade can be seen by the pedestrians, this is just the additional effect of the facade (can also be realized), its purpose is to let pedestrians to attract pedestrians into grocery Buy something. So a member function is PUBLIC, indicating that it is specifically used to be invoked by an external document to operate, usually a very adhered-action for such member functions. As mentioned earlier, the GET / SET member function should be public. A member variable is the public, like a member function, indicating that it is specifically operated outside. Such as the CWnd :: m_hwnd in the MFC is because the CWnd is a packaging class. Its packaging is the operation of the window handle m_hwnd, that is, the outside world knows that CWnd must have a member variable of a window handle, It is m_hwnd. The window handle forms a logical-window handle together in this and class CWnd, so cWnd :: m_hwnd is public. And the example of the example cabClist :: m_count why use the GET / SET function pair to operate without using public member variables? Because CabClist is a chain class class, the list itself does not have the number of elements. It can only get the number of elements, and the CabClist uses a member variable m_count to record the number of elements to speed up the number of elements, ie M_Count has some logical rules (guaranteed that their value is the number of linked lists), maintained by CabClist. So M_Count should be protected instead of public. In general, the properties of the meaning of the class should be PUBLIC, but if the attribute is associated, you should use the member function to package the properties to achieve the contact between attributes. Such as: The number of vertices of bit mappers, the number of polygonal stereoscopic models, and the number of polygon should not be public because they have a relationship with their respective implementations - bitmaps use a byte array, and the multilateral model uses vertex arrays And multilateral array. Changing the long width or the number of vertices requires the corresponding modification bytes or vertex arrays. The intelligent pointer is associated with the packaging of the pointer, and its packaging pointer does not contact the other member variables of the class, so the pointer member variable of its packaging should be public. Protected indicates that its modified member function or member variable cannot be seen by the outside, but can be seen by it. Again, not "can be seen", but "it is used." Still open the grocery store, the accounts in the store are not to see the pedestrians, and they are confidential for pedestrians. However, later the grocery store should be changed into a small supermarket, and the account is still used by the small supermarket. Here, the account is a member of protected. A member function is protected, indicating that it is specifically used to be called member function calls for member functions and derived classes to help operate class instances, usually such member functions are the auxiliary functions.

For example, the chain class CabClist In order to speed up the elements, it has a member function to sort the elements, which is used for alignment insertion operation and lookup operation, and its derived class is also possible to call it to order operation Therefore, this function should be protected. A member variable is protected, the members of the derived class can also operate it, dedicated to different usage of possible with the class. If a member variables can have different operations, such as the accounts of the front grocery store, when the small supermarket may cause different accounting forms due to support wholesale business, that is, the relevant information of wholesale is required, and the original The grocery store is not possible to record wholesale related information. Therefore, the member variable of the accounts of this grocery store should be protected. When it is not good to determine if the member variable will have different ways of operation, it is set to protected. Member variables are protected to protected that this base class provides more flexibility to its derived class, but it is also more risky - derived classes may result in the logic of the original developed. Private indicates that its modified member function or member variable can only be seen by itself (even if it is derived). Again, not "can be seen", but "it is used." The grocery store has a lease contract that means that the rental procedures of the store. For the use of it, it must be very careful. If the store manager decides to collect it, even if it will change the small supermarket, ask another business to take care of the supermarket, and still keep the contract by yourself. People who take care of the business can only handle the use of the lease contract through the store manager. This lease contract is private (this metaphor is not very appropriate). Private means that it can only be used by ourselves, the Private member function is a confidential behavior (such as the secret recipe of the pharmaceutical), and the Private member variable is a confidential item (such as the foregoing lease contract). A bit map class, which can add digital watermark to the bitmap thereof, and the member function generated by the watermark is an auxiliary function, and it is not intended to let the subclass can participate in improvement (although this is not a good Design), the generation and extraction of the watermark should be private. Rethinking the polygonal stereoscopic model, all the serial numbers of the vertex in the polygon array, acquire specific vertex positions through the vertex array. It is not intended that the subclass is not intended to change this relationship. Therefore, the vertex array and the multilateral array should be private, but this greatly limits the ability of subclasses, so some Protected member functions need to be provided. Help to process vertex arrays and multilateral arrays. This looks really extremely extreme, and its increased complexity is not general, and reduces efficiency, it is best to separately provide a structure in which vertex array and multilateral array are separately present (the structure only represents a memory layout, but class Different, although they don't differ, in addition to the default qualifiers, a public, a private, then derived from this structure. This is equivalent to defining the two arrays into public, but different. The original base class and the members of the two arrays will be further proposed to form a template class, and the structure is inherited with multiple inheritance, which is the separation of state and function, and is used in ATL. It looks very ridiculous, but it is only for a "should be private" to increase the complexity of the entire system, although the code may not increase. For this point, I can only say: The person who finally writes the code is myself. Mutable

As mentioned earlier, the member function that is logically should be a member function that still needs to modify the member variable. To this end, C provides Mutable's highly scented keywords. Mutable is used to modify a member variable to indicate that this member variable can be modified even in the Const member function, and give a specific example below. I have written a software that needs to process several resources (text, sound, video, polygon model). I provide a resource browsing bar like VC6, which is a list of list control boxes, showing the icons and names of each resource. Dissu to the view. Among them, for the polygon model, the icon is the reduction of the model to facilitate the use of the model. Due to the color and size limit of ICON, decide to select Bitmap as an expression of the icon. Therefore, a base class is provided, representing resources, which has a form: Class CResource: public cobject {... protected: mutable cbitmap m_bigicon; // Store instance icon Mutable cBitmap M_SMallicon; public: Virtual HbitMap Geticon (Bool Bbig = true) Conston ; // obtain the icon of a particular example ...}; because the icon of the resource instance does not change the necessity of the resource instance status, Geticon is constant, but because the icon is stored in the member variable of each instance to buffer the icon. (Don't have to create a bitmap every time and reduce icons - don't use a container to record each icon specifically), it is possible to modify m_bigicon or m_smallicon, but they are in the concept of resources. It is not related to the resource, and should not remove the CONST of Geticon because of this reason. Here, the role of mutable is got to ensure semantics. Global, static and member variables

Partial variables are temporary variables, equivalent to draft paper. Instead of temporary variables are global, static and members variables, which are mainly due to the different domains, and from semanticity is equivalent to the namespace where the name is different. The namespace is a very good thing that strictly illustrates the meaning of the function variables therebet, and can be nestled to indicate more complex semantics. Global variables indicate that this variable is used by all module files (ie, source files, .c / .cpp), such as the global application object in the MFC document / view structure program, each module file It can be used to extract resources or do other operations. Static global variables indicate that this variable is a function (including member functions) defined in the module file (which defines the module file), not the function of the entire project, such as writing a COM client, one The function creates a component, the CLSID of the component should be static global and only read (const) variables, which does not have the meaning of other module files in the project (and the application object of the MFC app has the entire project. Significance). Static member variables indicate that they are their class, which has special meaning, such as some MFC applications, such as the name of the remote server (configuration information should be stored in the registry, here assumes static Member variables make buffers), then there is always an application object for the MFC app, and the name of the remote server should be a static member variable of the application class in this MFC application - even if the instance of multiple applications still uses the same server. Name (actual light is a static member variable is not reaching this requirement). From this perspective, all global variables should be used as a member variable of the application class. assertion

As an assertion, it is necessary to be a language-independent technology, but it has an important position in the writing of code, and cannot be mentioned. As a result, the warning dialog is popped up due to the value of the code, but does not have any effects when the release is released. As an assertion indicates that the value of the corresponding expression should satisfy the conditions that the value of the expression is not satisfied. The general use of assertions is a lot of places to be helpful. In fact, the use of the use of the Const variable and the Const member function, "Help Debug" is just its additional effect, its true purpose is to express the logic of the code writer. As mentioned in the previous Const member function, if a programmer's code assertion fails, it means that his logic is confusing, or the code-protected code (ie, the following statement) has been wrong, or Assertional settings are not logical. At the beginning of each class's public member function, it should be asserted with the effectiveness of this (I use the Assert_Valid assertion macro in the MFC in front of the Get / Set function, and the assertions in the MFC use the assertion macro in the MFC). Because the public member function of the class is called by the outside world, the outside world may write: cabclist * pl = null; pl-> getcount (); // getcount, file fails this means that you have assumed yourself before each public member function This is a valid pointer, which is logically assumption, so it is necessary to expressed in an assertion. However, protection and privacy do not use this to protect it, because they must be called by themselves or sent class, which can be called, and they can be called, which means that the caller is effective, logically does not require the previous assumption. Cabclist has a protected member function DWORD SortElement (DWORD INDEX) Const, a given index represents the first element, while the returned DWORD represents the location of this element in accordance with the alignment method of the constituent. In sortelement, the first sentence should be the validity of INDEX: assert (Index

The semantics provided by C are often referred to in those mentioned above, and many of them have important semantics, such as virtual functions, overload functions, friends and expensive keywords, etc., the above is often ignored. . Finally, give an application example of semantics to illustrate its importance and guidance on code written. A simple program with a dialog that is constantly obtaining data from the COM and display the data into a curve. This is a very common model (if you replace the COM port into a compiler, it has become a compilation schedule from the compiler, and then display the compilation schedule on the status bar of the main window). It has two threads, and a work thread is responsible for continuously obtaining data and informs the dialog box display data, and a interface thread is responsible for the display of the dialog. Now, it is assumed to use the MFC writing, and there is an editing control on the dialog to continuously displays the true value of the latest data (such as water temperature). The dialog box is binding a float and that editing control through DDX in derived class, and there is an array that records historical data to draw curves. Here is a problem. The following thread function: DWORD WINAPI THREADPROC (Void * PDATA) // thread function, used to get data {// data acquisition cycle // data acquisition cycle // data from the COM port, Cabcdialog * PDIALOG = Reinterpret_cast (pdata); pdialog; pdialog-> m_data = i; pdialog-> Updatedata (false); // updatedata internal assert_valid (this) assertion failed} The calling statement assertion failed in the comment, but this is not this method In the event of a failure, the following is a semantic analysis why it fails, as for the assertion failure, if you are interested, see another article I wrote - "MFC Interface Package". A thread represents an object with a functionable object, which can automatically complete a series of tasks, such as automatic cash machine, automatic pipeline, etc. And people have subjective initiative, so there is an initiative, so it can be seen as a thread. When designing a multi-threaded program, it is best to look at each thread as a person, and then you can work with natural allocation. The previous working thread hypothesis is represented by A, and the interface thread is represented by B. Then a constantly inquire about the COM port, if there is data, then record the data on a card, then notify B by telephone or pressing the bell, then continue to ask Com ports (here assume that there is no interrupt function using the COM) . B is waiting, a phone or ringtone will immediately see the card (possibly passing the pipe to the B hand, it is more likely to use a business similar to the email), then draw the data on the board. Did you find a problem? That card is equivalent to the top of PDIALOG-> M_DATA (accurately, it is equivalent to i, where the existence of i is just to buffer, not transmissions), the problem is that M_Data is a member of B, and the card should be a And B is used, and after the member that turns B, it means that A must run to B in the place, fill in the card, and then go back.

Or the card is still transmitted like a pipeline just now, but the key to the problem is that this card is responsible for being a, not B, so if B is blocked or damaged, it will be respoted by A and then find a new one (but in code There is no problem, because the programmer does not have to consider the memory that is broken, this situation is an abnormality, and the thread will never make a temper). It will always feel unfair to a long A and B (A: Since I am responsible why he can use ? B: Why isn't it what I am responsible?). This is the blurred taste of authenticity. This looks very serious that the horn pointers are very serious. After all, there are many ways to implement the above algorithms, all have the same function, but which is better? If you see semantics, then this is worth it. Therefore, the problem is that m_data is a public member of CabcDialog, which should turn it to a static global variable (which is only used between CabcDialog and ThreadProc. If threadproc is replaced with the static member function of CabcDialog, this will be a big mistake, This logic and interface are mixed together, belonging to a bad design) or transform M_Data into CabcDialog, threadProc can only operate it by one SET function (turn off the ThreadProc read permissions), then send a message via SendMessage B. Top it uses Updatedata to do this, is wrong, indicating that the board is also responsible for painting, then B actually don't do anything (the top more of the murdable lives, handling the board, etc.). Let's take a semantic further optimization. Considering that it is easy to draw the data to the board, this B will do not do business for a long time, and a is idle (to monitor the movement of the COM), so I want to let A do not need to call or call each time after writing the card. (This saves the cost of the electric bell and the phone), but when you let B is idle, you will go to see if the data is updated. If you update it, take it back to draw the data on the board. But if b is not very idle, that is, it is not very frequent, it may lose data, so it is determined that the use of 3 cards, indicating that B cannot be missed 3 time periods. Now become M_Data [3], then call PDIALOG-> Updatedata to update the curve in the ONIDLE of the CWINAPP of B. This saves the overhead of sendMessage (thread switching, at least 1000 CPU cycles, A will hang the wait bit to confirm the message, and this time will relieve the buffer of the COM port), reduce the buffer of the COM port Since A does not miss the data due to the relationship of SendMessage (note, not interrupt mode). If the interface is more work (such as a small animation on the interface, such as Office's helper), it is equivalent to the board is complicated, B is not very idle, then the number of cards that missed the card will increase, but increase the complexity of the code. And unstable. At this point, you should use SendMessage as original, but in order to eliminate the overhead of SendMessage, you should use PostMessage instead. Therefore, when designing multithreaded programs, regarding each thread as a person, and the code is only the skills of people, and then it is its own level of performance.

转载请注明原文地址:https://www.9cbs.com/read-6306.html

New Post(0)