I learned about Delphi and my notes-processes and functions (Lecture 5)

Source: Internet
Author: User
Tags case statement

Routine is an important concept of Pascal. A routine is composed of a series of statements and its name is unique. You can call it multiple times through the routine name, in this way, only one routine is required in the program, which avoids repeated code and is easy to modify and maintain. From this perspective, you can think of routines as a basic code encapsulation mechanism. After introducing the syntax of the Pascal routine, I will go back and give an example to illustrate this problem.

Pascal process and functions

The routines in Pascal have two forms: process and function. In theory, the process is an operation that you require the computer to perform. A function is a calculation that can return values. The difference between the two lies in that the function can return the calculation result, that is, there is a return value, but the process does not. Both types of routines can contain multiple specified types of parameters.

But in fact, the function and process are not very different, because you can call a function to complete a series of operations and skip the returned value (use optional error code or something similar to the return value ); you can also pass the calculation result through the parameters in the process (this parameter is called a reference and will be discussed in the next part ).

The following example defines a process and two functions. The syntax of the two functions is slightly different and the results are identical.

procedure Hello;begin  ShowMessage ('Hello world!');end;function Double (Value: Integer) : Integer;begin  Double := Value * 2;end;// or, as an alternativefunction Double2 (Value: Integer) : Integer;begin  Result := Value * 2;end;

The popular practice is to assign the return value to the function using the Result instead of the function name. I think such code is easier to read.

Once these routines are defined, you can call them multiple times, where the call process can perform operations, and the call function can calculate the return value. As follows:

procedure TForm1.Button1Click (Sender: TObject);begin  Hello;end; procedure TForm1.Button2Click (Sender: TObject);var  X, Y: Integer;begin  X := Double (StrToInt (Edit1.Text));  Y := Double (X);  ShowMessage (IntToStr (Y));end;

Note:: Now you don't have to consider the syntax of the above two processes. They are actually methods. You only need to put two buttons on a Delphi Form and click them during the design phase. Delphi IDE will generate suitable support code, you only need to fill in the lines of code between begin and end. To compile the above Code, you must add an Edit control in the form.

Now let's go back to the Code encapsulation concept I mentioned earlier. When you callDoubleYou do not need to know the specific implementation method of the function. If a better double-multiple calculation method is found in the future, you only need to change the code of the function, and the code that calls the function does not need to be changed (although the code execution speed may be faster !).HelloThe same is true for the process. You can modify the program output by changing the code of the process,Button2ClickThe method automatically changes the display result. The changed code is as follows:

procedure Hello;begin  MessageDlg ('Hello world!', mtInformation, [mbOK],0);end;

Prompt: When calling an existing Delphi function, process, or any VCL method, you should remember the number of parameters and their data types. However, as long as you type the function or process name and left parenthesis, a prompt bar appears in the Delphi editor to list the parameter tables of the function or process for your reference. This feature is called a code parameter (Code Parameters)Is part of the code recognition technology.

Reference parameters

The passing parameter of the Pascal routine can be a value parameter or a reference parameter. Value parameter passing is the default parameter passing method: the copy of the value parameter is pushed into the stack. The routine uses and operates the copy value in the stack, not the original value.

When passing parameters through reference, the parameter value is not copied to the pressure stack in the normal way (avoiding copying the value pressure stack can generally speed up program execution), but directly referencing the original parameter value, the code in the routine also accesses the original value, so that the parameter value can be changed in the process or function. Keyword used to reference parametersVarMark.

Parameter reference technology is available in most programming languages. Although it is not in C language, it is introduced in C ++. In C ++, use the symbol & to indicate the reference. In VB, noByValAll the marked parameters are references.

The following is an example of passing parameters by reference.VarKeyword:

procedure DoubleTheValue (var Value: Integer);begin  Value := Value * 2;end;

In this case, the parameter passes a value to the process and returns the new value to the code of the call process. When you finish executing the following code:

var  X: Integer;begin  X := 10;  DoubleTheValue (X);

The value of the x variable is 20 because the process accessesXThe original storage unit, thus changingX.

Passing parameters by reference makes sense to the ordered type, Traditional string type, and large record type. In fact, Delphi always transmits objects through values, because the Delphi object itself is a reference. Therefore, passing an object through a reference is meaningless (except in special cases), because it is equivalent to passing a reference to another reference.

Delphi long strings are slightly different. long strings look like references, but if you change the string variable, the string will be copied Before update. The long string passed as a value parameter is referenced only in terms of memory usage and operation speed. However, if you change the value of the string, the initial value will not be affected. On the contrary, if a long string is passed by reference, the initial value of the string can be changed.

Delphi 3 adds a new parameter: out. The out parameter has no initial value, but is used to return a value. The out parameter should only be used for COM procedures and functions. Generally, it is best to use more effective var parameters. Except for no initial value, the out parameter is the same as the var parameter.

Constant Parameters

In addition to referencing parameters, there is also a constant parameter. Since it is not allowed to assign new values to constant parameters in a routine, the compiler can optimize the transfer process of common parameters. The compiler will use a method similar to the reference parameter to compile the constant parameter (constant reference in C ++ terminology), but on the surface, the constant parameter is similar to the value parameter, because the initial values of common parameters are not affected by the routine.

In fact, if you compile the following code, Delphi will get an error:

function DoubleTheValue (const Value: Integer): Integer;begin  Value := Value * 2;      // compiler error  Result := Value;end;
Open array parameters

Unlike the C language, the number of parameters of Pascal functions and procedures is predefined. If the number of parameters is not determined in advance, you need to pass the parameters through open arrays.

An open array parameter is an element of a fixed Type Open array. That is to say, the parameter type has been defined, but the number of elements in the array is unknown. See the following example:

function Sum (const A: array of Integer): Integer;var  I: Integer;begin  Result := 0;  for I := Low(A) to High(A) do    Result := Result + A[I];end;

The above uses High (A) to get the size of the array. Pay attention to the application of the Result returned by the function. The Result is used to store the temporary value. You can call this function through an array composed of integer expressions:

X := Sum ([10, Y, 27*I]);

Given an integer array with any array size, you can directly pass it to a routine with open array parameters. In addition, you can alsoSliceFunction, only pass a part of the elements of the array (the number of transmitted elements is determinedSliceThe second parameter of the function ). The following is an example of passing the entire array parameter:

var  List: array [1..10] of Integer;  X, I: Integer;begin  // initialize the array  for I := Low (List) to High (List) do    List [I] := I * 2;  // call  X := Sum (List);

If you only pass part of the array, you can use the Slice function as follows:

X := Sum (Slice (List, 5));

In Delphi 4, open arrays of the given type are fully compatible with dynamic arrays (dynamic arrays will be introduced in chapter 8th ). The syntax of dynamic arrays is the same as that of open arrays. The difference is that you can useArray of IntegerThe command defines variables, not just passing parameters.

Open array parameters for type changes

In addition to fixed open arrays, Delphi also allows you to define open arrays with or without type changes. This special type of array elements can be changed at will and can be easily used as parameters for passing.

Technically, arrays of the const type can be used to transfer an array consisting of different types and numbers of elements to a routine. See the following Format Function Definition (in chapter 7, you will see how to use this function ):

function Format (const Format: string;  const Args: array of const): string;

The second parameter above is an open array, which can be changed at will. You can call this function as follows:

N := 20;S := 'Total:';Label1.Caption := Format ('Total: %d', [N]);Label2.Caption := Format ('Int: %d, Float: %f', [N, 12.4]);Label3.Caption := Format ('%s %d', [S, N * 2]);

As shown in the preceding figure, the passed parameter can be a constant value, a variable value, or an expression. It is easy to declare such functions, but how to compile the function code? How do I know the parameter type? Open arrays with variable types. The array elements andTVarRecType element compatibility.

Note:: Do not setTVarRecRecord type andVariantType UsedTVarDataThe record type is confusing. These two types have different purposes and are not compatible with each other. Even the data types that can be accommodated are different becauseTVarRecSupports the Delphi data type, while TVarData supports the OLE data type.

TVarRecThe record type structure is as follows:

type  TVarRec = record    case Byte of      vtInteger:    (VInteger: Integer; VType: Byte);      vtBoolean:    (VBoolean: Boolean);      vtChar:       (VChar: Char);      vtExtended:   (VExtended: PExtended);      vtString:     (VString: PShortString);      vtPointer:    (VPointer: Pointer);      vtPChar:      (VPChar: PChar);      vtObject:     (VObject: TObject);      vtClass:      (VClass: TClass);      vtWideChar:   (VWideChar: WideChar);      vtPWideChar:  (VPWideChar: PWideChar);      vtAnsiString: (VAnsiString: Pointer);      vtCurrency:   (VCurrency: PCurrency);      vtVariant:    (VVariant: PVariant);      vtInterface:  (VInterface: Pointer);  end;

Each record hasVTypeAt first glance, it is not easy to find, because it is put together with the actual Integer type data (usually a reference or a pointer) and is declared only once.

With the above information, we can write a function that can operate on different types of data. In the following exampleSumAllFunction, calculate the sum of different data types by converting a string into an integer, a character into a corresponding serial number, and a True Boolean value plus one. This code is based on a case statement. Although it has to pass the pointer value frequently, it is quite simple ,:

function SumAll (const Args: array of const): Extended;var  I: Integer;begin  Result := 0;  for I := Low(Args) to High (Args) do    case Args [I].VType of      vtInteger: Result :=        Result + Args [I].VInteger;      vtBoolean:        if Args [I].VBoolean then          Result := Result + 1;      vtChar:        Result := Result + Ord (Args [I].VChar);      vtExtended:        Result := Result + Args [I].VExtended^;      vtString, vtAnsiString:        Result := Result + StrToIntDef ((Args [I].VString^), 0);      vtWideChar:        Result := Result + Ord (Args [I].VWideChar);      vtCurrency:        Result := Result + Args [I].VCurrency^;    end; // caseend;

I have added this code in the OpenArr example. This example is called after you press the set button.SumAllFunction.

procedure TForm1.Button4Click(Sender: TObject);var  X: Extended;  Y: Integer;begin  Y := 10;  X := SumAll ([Y * Y, 'k', True, 10.34, '99999']);  ShowMessage (Format (    'SumAll ([Y*Y, ''k'', True, 10.34, ''99999'']) => %n', [X]));end;

Delphi Call Protocol

A new parameter transfer method is added to 32-bit Delphi, called fastcall: as long as possible, three parameters can be transferred to the CPU register, making function call operations faster. This fast call Protocol (in the Delphi 3 mode) can be identified by the register keyword.

The problem is that this fast call protocol is not compatible with Windows, and Win32 API functions must declare the use of stdcall to call the protocol. This protocol is a mixture of original Pascal call protocols used by Win16 APIs and cdecl call protocols used by C languages.

Unless you want to call an external Windows function or define a Windows callback function, you have no reason not to add a new quick call protocol. You will see an example of using the stdcall Protocol later. Under the Calling conventions topic in the Delphi help file, you can find the summary about the Delphi call protocol.

What is a method?

If you have used Delphi or read the Delphi manual, you have probably heard of the term "method. A method is a special function or process that corresponds to the Data Type of the class. In Delphi, each time an event is processed, a method must be defined. This method is usually a process. However, generally, "methods" refer to class-related functions and processes.

You have seen several methods in this chapter and the previous chapters. The following is an empty method that Delphi automatically adds to the form source code:

procedure TForm1.Button1Click(Sender: TObject);begin  {here goes your code}end;
Forward statement

When using an identifier (of any type), the compiler must already know what it refers. Therefore, you usually need to provide a complete declaration before the routine is used. However, in some cases, this may not be possible. For example, if process A calls process B and process B calls process A, when you write process code, you have to call the compiler to see the declared routines.

To declare a process or function, and only give its name and parameters, without listing its implementation code, add the forward keyword at the end of the sentence:

procedure Hello; forward;

The complete code of the process should be completed later, but the location of the Process Code does not affect its calling. The following example has no practical significance. After reading it, you will understand the above concepts:

procedure DoubleHello; forward;procedure Hello;begin  if MessageDlg ('Do you want a double message?',      mtConfirmation, [mbYes, mbNo], 0) = mrYes then    DoubleHello  else    ShowMessage ('Hello');end;procedure DoubleHello;begin  Hello;  Hello;end;

The preceding method can be used to write recursive calls:DoubleHelloCall Hello, and Hello may also callDoubleHello. Of course, the condition must be set to terminate this recursion to avoid stack overflow. The above code can be found in the DoubleH example, but it is slightly changed.

Although the forward process declaration is not common in Delphi, a similar situation often occurs. When you declare a process or function in the interface section of a unit (for more information about the Unit, see the next chapter), it is considered as a forward statement, the same is true even if there is no forward keyword. In fact, you cannot put the entire routine code in the interface part, but you must provide the declared routine implementation in the same unit.

The method declaration inside the class is also the forward Declaration. When you add events to the form or its components, Delphi will automatically generate the corresponding code. The event declared in the TForm class is the forward declaration, and the event code is placed in the implementation part of the unit. The source code extracted below contains a Button1Click method declaration:

type  TForm1 = class(TForm)    ListBox1: TListBox;    Button1: TButton;    procedure Button1Click(Sender: TObject);  end;
Process type

Another unique feature of Object Pascal is the definable process type. The process type is an advanced function of the language, which is not frequently used by Delphi programmers. This is because the subsequent sections will discuss relevant content (especially the "method Pointer" Delphi is used a lot). Here we may take a look at it first. If you are a beginner, you can skip this section and read it back after learning a certain degree.

The process type in Pascal is similar to the function pointer in C. The Declaration of the Process type only requires the parameter list. If it is a function, a return value is added. For example, declare a process type with an integer parameter passed by reference:

type  IntProc = procedure (var Num: Integer);

This process type is compatible with routines with identical parameters (or has the same function feature in C language ). The following is a compatibility routine:

procedure DoubleTheValue (var Value: Integer);begin  Value := Value * 2;end;

Note:: In 16-bit Delphi, to use a routine as the actual value of the process type, you must use the far command to declare the routine.

The process type can be used for two different purposes: declare a variable of the Process type; or pass the process type (that is, the function pointer) as a parameter to another routine. With the given type and Process Declaration above, you can write the following code:

var  IP: IntProc;  X: Integer;begin  IP := DoubleTheValue;  X := 5;  IP (X);end;

This code is equivalent to the following code:

var  X: Integer;begin  X := 5;  DoubleTheValue (X);end;

The first piece of code above is obviously complicated. Why should we use it? In some cases, the program type is useful when you decide what type of function to call. A complex example cannot be created here to illustrate this problem. However, you can look at a simple example named ProcType. This example is more complex than the previous example and closer to practical application.

As shown in Figure 6.3, create a project and put two radio buttons and one push button on it. In this example, there are two processes. One process doubles the parameter valueDoubleTheValueThe process is similar. Another process doubles the parameter value and is named TripleTheValue.

procedure TripleTheValue (var Value: Integer);begin  Value := Value * 3;  ShowMessage ('Value tripled: ' + IntToStr (Value));end;

The results of both processes show that they have been called. This is a simple program debugging technique. You can use it to detect whether or when a code segment is executed, rather than adding breakpoints to the code.

When you press the Apply button, the program selects the execution process based on the radio button status. In fact, when there are two radio buttons in the form, you can only select one, so you only need to add the code to check the value of the radio button in the OnClick event of the Apply button to implement the program requirements. However, in order to demonstrate the use of the Process type, I chose the troublesome but interesting method: as long as the user selects one of the radio buttons, the corresponding process of the button will be saved to the process variable:

procedure TForm1.DoubleRadioButtonClick(Sender: TObject);begin  IP := DoubleTheValue;end;

When you press the Apply button, the program executes the process of saving process variables:

procedure TForm1.ApplyButtonClick(Sender: TObject);begin  IP (X);end;

To enable three different functions to access IP addresses and X variables, the variables must be visible in the entire form unit, so they cannot be declared as local variables (declared in a method ). One solution is to place these variables in the form declaration:

type  TForm1 = class(TForm)    ...  private    { Private declarations }    IP: IntProc;    X: Integer;  end;

After completing the next chapter, you will have a better understanding of the meaning of this Code. Currently, you only need to know how to add the process type definition and modify the corresponding code. To initialize the two variables in the above Code with appropriate values, you can call the OnCreate event of the form (after activating the form, select this event in the Object Inspector, or double-click the form ). In addition, it is best to take a closer look at the complete source code of the above example.

In the Windows callback function section described in 9th, you can see the instances using the process type.

Function overload

The idea of overloading is simple: the compiler allows you to define multiple functions or processes with the same name, as long as they have different parameters. In fact, the compiler uses detection parameters to determine the routines to be called.

The following are a series of functions extracted from the Math Unit of VCL:

function Min (A,B: Integer): Integer; overload;function Min (A,B: Int64): Int64; overload;function Min (A,B: Single): Single; overload;function Min (A,B: Double): Double; overload;function Min (A,B: Extended): Extended; overload;

When the call method is Min (10, 20), the compiler can easily determine that you are calling the first function in the upper column. Therefore, the return value is an integer.

There are two principles for declaring overload functions:

  • The overload keyword must be added after each routine declaration.
  • The number or type of parameters between routines must be different. The return value cannot be used to distinguish between routines.

The following are three reload processes of the ShowMsg process. I have added them to the example OverDef (an application that describes overload and indeed saves parameters ):

procedure ShowMsg (str: string); overload;begin  MessageDlg (str, mtInformation, [mbOK], 0);end;procedure ShowMsg (FormatStr: string;  Params: array of const); overload;begin  MessageDlg (Format (FormatStr, Params),    mtInformation, [mbOK], 0);end;procedure ShowMsg (I: Integer; Str: string); overload;begin  ShowMsg (IntToStr (I) + ' ' + Str);end;

The three procedures format strings in three different ways, and then display the strings in the information box. The following is the call of three routines:

ShowMsg ('Hello');ShowMsg ('Total = %d.', [100]);ShowMsg (10, 'MBytes');

I was pleasantly surprised by the combination of Delphi's code parameter technology and heavy load processes and functions. When you enter left parentheses after the routine name, the window displays a list of parameters for all available routines. When you enter parameters, delphi filters the parameter list based on the type of the input parameter. As you can see in Figure 6.4, when you start to input a constant string, Delphi only displays the list of two ShowMsg Routine Parameters whose first parameter is the string, and filters out the routines whose first parameter is an integer.

The overload routine must be explicitly identified by the overload keyword. You cannot reload the routines without the overload label in the same unit; otherwise, an error message will appear: "Previous declaration of '<name> 'was not marked with the 'overload' ctictive. ". However, you can reload the routines declared in other units to be compatible with the previous Delphi version. The previous Delphi version allows different units to reuse the same routine name. In any case, this is a special case of routine overloading, not a special feature, and problems may occur accidentally.

For example, add the following code to a unit:

procedure MessageDlg (str: string); overload;begin  Dialogs.MessageDlg (str, mtInformation, [mbOK], 0);end;

This Code does not really reload the original MessageDlg routine. If you type:

MessageDlg ('Hello');

You will get an interesting error message indicating that the parameter is missing. The only way to call a local routine instead of VCL is to clearly identify the unit where the routine is located, which is contrary to the idea of routine overloading:

OverDefF.MessageDlg ('Hello');

Saving Parameters

In Delphi 4, a new function is added, that is, you can set a saved value for the function parameters. In this way, this parameter can be added or omitted when a function is called. In the following example, we rewrap the MessageBox method of the entire object of the application, replace the string with PChar, and set two savings values:

procedure MessBox (Msg: string;  Caption: string = 'Warning';  Flags: LongInt = mb_OK or mb_IconHand);begin  Application.MessageBox (PChar (Msg),    PChar (Caption), Flags);end;

With this definition, you can use any of the following methods to call the process:

MessBox ('Something wrong here!');MessBox ('Something wrong here!', 'Attention');MessBox ('Hello', 'Message', mb_OK);

As you can see in Figure 6.5, the prompt bar of Delphi code parameters will display the saved value parameters in different styles, so that you can easily determine which parameter can be omitted.

Note that Delphi does not generate any special code that supports Parameter validation, nor create multiple copies of the routine. The default parameter is added to the Code of the calling routine by the compiler during compilation.

An important limitation of using a parameter is that you cannot "Skip" The parameter. For example, if you omit the second parameter, you cannot pass the third parameter to the function:

MessBox ('Hello', mb_OK); // error  

If you want to omit a parameter, you must omit all its parameters.

The usage rules for indeed saving parameters include:

  • Parameters with saved values must be placed at the end of the parameter table.
  • The saved value must be a constant. Obviously, this limits the Data Type of the province parameter. For example, the province parameter value of the dynamic array and interface type can only be nil; as for the record type, it cannot be used as the province parameter at all.
  • The parameter must be passed through the value parameter or common parameter. The reference parameter var cannot have default values.

If you use both real-time parameters and overload functions, problems may occur because these two functions may conflict. For example, change the previous ShowMsg process:

procedure ShowMsg (Str: string; I: Integer = 0); overload;begin  MessageDlg (Str + ': ' + IntToStr (I), mtInformation, [mbOK], 0);end;

The compiler does not give warnings during compilation because this is a legal definition.

However, compile the call statement:

ShowMsg ('Hello');

The compiler displaysAmbiguous overloaded call to 'showmsg'.(Not explicitly reload ShowMsg). Note: This error message points to the line before the newly defined code for the reload routine. In fact, the ShowMsg process cannot be called with a string parameter, because the compiler does not know whether you want to call the ShowMsg process with only the string parameter or the process of saving parameters with the string and Integer Parameters. In this case, the compiler has to stop and ask you to clarify your intention.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.