Use macro command to transform BCB - Implement the class C # Property declaration syntax GOLDROC in BCB
Primer
Hailing procedures, hi BCB (Borland C Builder). See the property statement of C # on one day, and feel refreshed. Thereafter, there will be, and it is completely organized, and the name of the crown article is used. The husband is like a good and bcb, or can be beneficial. If it is, it is a purpose.
Background Description - Macro's historical position
After the object-oriented C language is launched, an extremely important macro command once in C seems to be rarely used. Even C Master Bjarne Stroustrup is also said in his classic C tutorial "THE C Programming Language" said: "About Hong's first rule is: Never use it, unless you have to do this. Because it will The compiler sees the text of the program before resending these text. "Even the most used defined constants used in C has a new keyword const, plus other inline, template, enum, namespace mechanism, etc. In order to use many traditional ways of use of the pretreatment structure. However, Bjarne Stroustrup also admits that we can design your private language using macros. As long as it makes our work simplify, it is a useful macro. "You can design your own private language", what does it mean for us? How do I use it to transform existing languages to simplify our work? Of course, the so-called simplification is inextricably complicated. So as long as it is an original grammatical, we can use macro to simplify it. A good typical is the property declaration syntax in the BCB.
Background Description - BCB and C # properties Declaration Syntax
To declare an attribute in the class declaration of the BCB, you must first declare a store of a property data - a data member. Of course, in general, it is declared in private partial. Then there are some other operations when reading or writing properties, then declare the method of reading or writing attributes. Generally speaking, in order to ensure the legal line of data, there is often at least one write property method. Finally, I have to release it in public or __publish (components) to be visible by the user of the class. Let's take a look at the specific code. Suppose a girl CGIRL, has a beautiful index property prettiness, and the range is 0-3.0: its ugly is incomparable; 1: Malays and tiger; 2: Decorated Tiger 3: Drama Allure. Then you have to write this in BC: header file cgirl.h Class cgirl {public: __property int prettiness = {read = fgetprettiness, Write = fsetprettiness}; ... // (following other public members) Private : Int FPRETTINESS; ... // (去 去 私 成;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Code file in CGirl.cpp int __fastcall CGirl :: FGetPrettiness () {return FPrettiness;} void __fastcall CGirl :: FSetPrettiness (int vPrettiness) {if (vPrettiness <= 3 && vPrettiness> = 0) FPrettiness = v FPrettiness;} ......
For simple classes, this definition may not be too trouble. The definition of the attribute can be clear. But if the class is slightly complicated - the specific point is if it is a 1000-line class? (Sweating) The result is often turned back in the Nobi Code, which is the definition of reading and writing methods related to a property. Now, after the release of Microsoft .NET, .NET Framework suddenly became the most popular stuff. It hits it in unstoppable potential. Moreover, Microsoft has told the SUN Java, nor does it take care of the progral of the programming language, and a new language is added in Visual Studio. I don't want me to say that everyone knows - pair is it: C #, another and C syntax very similar language. There is too much story for .NET and C #, it is impossible to say it here. However, C #'s grammar for attribute declarations has left a deep impact on the author. This is precisely what we are concerned about today. Take a look at the C # property declaration syntax. As an example in the same way, it may be the following as an example, use C # written like this: class cgirl {private int wprettiness; public int prettiness // Define Properties {Get // Read Properties method {Return FPRETTINESS;} set // write attribute Method {IF (value <= 3 && value> = 0) fprettiness = value;}}} Don't use me more, it is very obvious. Below, let's take a look at how to make the complicated property declare syntax as C # simply through the macro command. This is not a trick, but it is a little fine.
Technical basis - macro definition grammar
First, we have to understand the definition format of the macro: #define
For example, a declaration with a ginseng macro: #define Writen (a) cout << a << Endl is in the code, if you write: Writen ("Use the macro command, transform C builder"); then, after the macro expansion It will become like this: COUT << "clever uses macro command, transform C builder" << Endl; this is the expansion of the envelope macro, is not complicated. In order to turn the properties of the BCB into C #, we also need to know two operators: / and ##. 1, / Operator: When a macro defined extension content is more than a line of connectors. If you want to write a macro definition, add it on the tail. Such as: #define Title uses a macro / order to transform C Builder
Equivalent to: #define title with macro command, transform C Builder
2, ## operator: Parameter extension connector. It can connect the previous content and parameters into a whole without intervals. Or come to see the example: Define a macro: #define var (i, j) (i ## j) So if you write this in the code: VAR (x, 6), it will be expanded to x6. Using this feature we can modify a given macro parameter in order to adapt to our requirements.
Technology implementation - start retrofit BCB
The foundation is so much, then take a look at what needs to be used to transform BCB. First, determine the name of the macro, here is a macro name for Temporary. Next, determine the parameters of the macro. Our purpose should make the macro and the syntax of the C #, then how many macros should be like this: Property (attribute visibility property type property name {get {// read attribute code} set {// write property code }}) However, although the pseudo code above is closest to the C # syntax, it is not possible to define the appropriate macro. The reason is that some important parameter elements needed by the macro cannot be separated from the overall code. The so-called important parameter elements are "visibility", "attribute type", "element", "read property code part", "Write Properties section", as described above. The above pseudo code starts from "visibility" from "attributes until the last brace is a whole, becoming a parameter. This naturally cannot be expanded correctly. We should separate these five important elements into one parameters. Of course, the more similar, better in the form of the pseudo code above: Property (attribute visibility, attribute type, attribute name, get {// read attribute code }, Set {// write attribute code})
This reaches the requirements of each element and independently becomes a macro parameter.
Then, we will design this macro on the form of the above usage. First give each element of the above, it is: the visibility of the attribute pregion property type PTYPE attribute name PNAME read property code PgetMethod write property code PsetMethod
Remember two method functions required to declare a property in BCB, respectively, read and write. A fixed function name must be used in the macro definition, and must be related to the property name. This way we are set to form a FGET and FSET in front of the attribute name to form a read / write method function, and the parameters of the write method (the new value of the corresponding attribute) are always Value (as in C #). Definition in the macro: // Read method function ptype __fastcal fget ## pname () PgetMethod // write method function void __fastcall fset ## pname (ptype value) PsetMethod
Don't forget that there is another property publishing statement: __property ptype pname = {read = fget ## pname, Write = fset ## pname};
To finish, the statement of macro finally became the following: Property (Pregion, PTYPE, PNAME, PGETMETHOD, PSETMETHOD) / Private: / Ptype Fget ## PName () / PgetMethod / Void Fset ## pname (ptype value) / PsetMethod / Pregion: / __property ptype pname = {/ read = fget ## PNAME /, WRITE = fset ## PNAME /};
Note: In the use of the macro, the read or write method functions also have a GET or SET identifier, and they must be blocked, otherwise it is not possible to form a complete function implementation by adding PgetMethod or PsetMethod to the function declaration after the function declaration. By following the two macro declarations to block GET or SET: #define get #define set here, this macro definition is basically successful. However, since the attribute may have read-only, only written or no read method functions (many attributes can only read the value of the member data, no additional code) is different, we also need another few Macros can be applied to these situations. See the specific code. Finally, several places worthy of special attention are used: 1. Pay attention to the comma of each macro parameter, especially between GET and SET methods, cannot be missed. 2, pay attention to the GET and SET methods implementation cannot be reversed. Complete implementation - specific code
GOLDROC OPUS ///// Property Defines Macros (for C Builder) // Description: Infitable the property declaration syntax // (header file) // defines the readable write properties: Property (attribute visibility, attribute type, Property name, read attribute code, write property code // Define read-only properties: Property_ReadOnly (Property visibility, attribute type, attribute name, reading property code) // Define only write properties: Property_Writeonly (property visibility, attribute type, Property name, write attribute code) // Define an attribute macro that does not require a read method: Property_Direct_read (attribute visibility, attribute type, attribute name, attribute data, write property code) // Define read-only properties that do not need to read methods Macro: Property_Direct_read (Attribute Visibility, Property Type, Property Name, Property Corresponding Data) ///////> The following macro definition general rules are as follows: // Place the member variable of the property data in the private, name to attribute Preferred F // Place the function of the member variable of the attribute data in private, name is previously fed or fset // row reference name value //, such as: attribute int left // Property // Public, int, left, // Get // {// Return_LEFT; // Prepare the prefix before the attribute list _ indicate the current value of the attribute //} // // Note this comma can not be lost !!! // SET / / {// _left = value; // The new value is value ///} //) //// Note: GET and SET methods cannot be reversed! /// / read-only attribute int =/ (public, int, left, // get // {// Return_LET; // Preferred in the attribute prefix _ indicate the current value of the attribute //} // ) // ----------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------- ----- # iFNDef Property_Macroh # Define Property_Macroh // -------------------------------------- -------------------------------------- # Define get / * get * / # define set / * set * /
#define PROPERTY (pRegion, pType, pName, pGetMethod, pSetMethod) / private: / pType FGet ## pName () const / pGetMethod / void FSet ## pName (const pType & value) / pSetMethod / pRegion: / __property pType pName = { / Read = fget ## PNAME /, WRITE = FSET ## PNAME /};
// read-only attribute macro #define property_readonly (pregion, ptype, pname, pgetMethod) / private: / ptype fget ## pname () const / pgetMethod / pregion: / __property ptype pname = {/ read = fget ## PNAME /} ; // only write attribute macro #define property_writeonly (pregion, ptype, pname, psetMethod) / private: / void fset ## PNAME (const ptype & value) / psetMethod / pregion: / __property ptype pname = {/ write = fset ## PNAME /}; // does not need to read the property macro #define property_direct_read (Pregion, Ptype, PNAME, PDATA, PSETMETHOD) / PDATE: / VOID FSET ## PNAME (Const Ptype & Value) / PsetMethod / Pregion: / _ _property ptype pname = {/ read = pdata /, write = fset ## pname /}; // does not need reading method read-only property macro #define property_direct_readonly (pregion, ptype, pname, pdata) / pregion: / __property ptype pname = {/ Read = pdata /}; # endif // ------------------------------------- ------------------------------------- (the above code is debugged in BCB6)