Delphi programming OOP thought "turn"

Source: Internet
Author: User

Original: http://blog.sina.com.cn/s/blog_9c47a15201015rew.html

Note: This digest since http://blog.csdn.net/haiou327/article/details/5937171, reprint please specify;

Good things to share with you

Just contact with the Delphi friend, probably the most interesting is its rich, powerful VCL (visual Component Library). It's exciting to just throw a few artifacts into the form, and not even write code, to easily make a useful program. However, VCL is only a small part of Delphi, Delphi's excellence is far more than the performance of the VCL. If you just stay in the use of VCL, then you will never be a real Delphi master. Remember, you must go beyond VCL to be able to reach the heart of Delphi.
So, what is hidden behind the vcl of Delphi? This article discusses two more advanced Delphi topics: OOP and database programming.
This article assumes that the reader already has the basic knowledge of Delphi programming, for example, familiar with the general syntax of Pascal Language, master the simple VCL use, will use the Data-ware component to write basic database programs, and so on. This article does not duplicate the use of VCL for this issue.
  
1. OOP
  
The English full name of OOP is the object oriented programming, which translates to OO programming. OOP is a very important programming idea. Perhaps you will not be interested in this abstraction, but almost any master will tell you: "Language is not important, the important thing is the idea of programming." ”
As you know, Delphi's language base is Object Pascal. This is Borland in the traditional Pascal language with the addition of object-oriented features developed, and specifically named Object, to show the difference with the traditional Pascal language, it can be seen that object-oriented technology on its impact. It can be said that Delphi is built on the basis of Object Pascal, while Object Pascal is built on object-oriented technology.
In fact, not only Delphi,oop is also the foundation of many other modern programming languages, such as C + +, Java (Visual Basic does not fully support OOP). Mastering the OOP technology skillfully is the necessary condition for mastering Delphi, and it is the only way to enter the master realm, and it is also one of the symbols of a mature programmer. With the understanding of OOP technology, many of the things that have puzzled you before can be solved.
Interestingly, although Delphi is completely OOP-based, a programmer who knows nothing about OOP can also use Delphi to write programs, because Delphi does most of the work automatically. When you start learning about Delphi, you may not be able to imagine how complex a task Delphi will be when you simply add a button to a form. But since we are interested in going into the world of Delphi and becoming a real programmer, we should be curious about the details of Delphi.
These theories may be boring and intimidating, but you will feel nothing when you have mastered them. Of course, you need to have enough willpower.
There are three main features of OOP:
  
1.1 Data Encapsulation
  
Let's look at a piece of code first:
  
Type
Tdate = Class
Mouth,day,year:integer;
Procedure SetValue (M,d,y:integer);
function Leapyear:boolean;
End
  
We will first see the Class keyword, which is named "Class" in Chinese. Class is a very important concept. According to the definition of authority, a class is a user-defined data type that has its own description and some operations. A class contains some internal data and some object methods in the form of procedures or functions, usually to describe common characteristics and behaviors of some very similar objects.
This definition can be quite obscure. You can think of a class as a special record type, which may contain not only data, but also functions and procedures (called Methods in OOP). These data and methods are collectively referred to as members of the class.
The above class is obviously a date type, which includes the Mouth,day,year three data members, and the SetValue, Leapyear two methods. Incidentally, in Delphi, the use of the letter T as a prefix for each class, as in Viusal C + +, is used as the prefix for each class in the letter C.
Mouth,day,year These three data members specify the year, month, and day of the date. The SetValue method assigns values to these three data members, and leapyear checks whether the year in which the current date resides is a leap years. Here are some of the implementations of the two methods:
  
Procedure Tdate.setvalue (M,d,y:integer);
Begin
Mouth: = m;
Day: = D;
Year: = y;
End
  
function TDate.LeapYear:Boolean;
Begin
if (year mod 4 <> 0) Then
Leapyear: = False
else if (year mod <> 0)
Leapyear: = True
else if (year mod <> 0)
Leapyear: = False
Else
Leapyear: = True;
End
  
Once these definitions have been implemented, they can be called as follows:
  
Var
Aday:tdate;
Begin
Create an Object
Aday: = tdate.create;
Use of
Aday.setvalue (1,1,2000);
If Aday.leapyear Then
ShowMessage (' Leap year: ' + inttostr (aday.year));
Releasing objects
Aday.free;
End
  
Let's explain the meaning of the code row by line. The line after Var declares a variable of the Tdate class.
After declaring a variable, how do we use it? Use the Create method of the Tdate class to create an object of that class and assign it to the Aday variable.
Now we are exposed to another important concept in OOP: objects. What is an object? In short, an object is an instance of a class, or a variable of a class-defined data type. When an object of a class is established, the system allocates a piece of memory to it. For example, if we define a variable A as an integer type, then integer is a data type and a is an instance. The relationship between a class and an object is similar to the relationship between the two. It's important to differentiate between classes and objects, and even some professional programmers tend to confuse them.
The attentive reader may notice that in the definition of the Tdate class, there is no create this method. So where does this create method come from? The Create method is an implicit method for each class, and its purpose is to create an instance of the class. Note that in this case, the classes and other data types are different. Other data types can be used directly after the variable is declared, and the class type must be used after the instance (object) that created it using the Create method.
In fact, in C + + and most other OOP languages, declaring a variable of a class can create objects of that class at the same time. While Delphi (including its twin brother C + + Builder) is different in this regard, it must be created to actually build the object. At the same time, when this object is no longer needed, you must manually call the free method to release the object (of course, it is implied by each class). This and Delphi's unique "object Reference Model", interested friends can consult the relevant information, I will not say more.
This situation is a very interesting phenomenon, that is, programmers often forget to create it before using the object, thereby making an error, but from C + + to Delphi Master also often make the same mistake ...
By the way, the trick is that when the compiler comes up with a "Read of address:ffffffff" error, it's mostly because you forgot create before using the object, and you can check the code from there. Also, do not forget to use free when you do not need it, or it may cause a memory leak.
In the middle of the code that creates and frees objects, it is the code that uses the object. Accessing the data members of an object is very simple and does not differ from the record type. You can access them by a dot-expression:
  
Aday.year: = 2000;
Aday.mouth: = 1;
Aday.day: = 1;
  
Similarly, you can use a dot expression to invoke the method of an object. If you read the code of the method implementation section, you can easily find that the sentence Aday.setvalue (1,1,2000) is assigned a value of three data members, and the aday.leapyear call returns whether the current date is in a leap year. At this point, the meaning of the whole piece of code is clear.
However, classes are not just that simple. The above example is a very simple class that can directly access any of its members (data and methods). However, members of certain classes cannot be accessed casually. Delphi uses three keywords to differentiate the access rights of these members:
  
Table 1


Private members of this type can only be accessed in the declaring class
Public this type of member can be accessed by code anywhere in the program
Protected members of this type can be accessed only in declared classes and in derived classes that declare classes


  
Protected types of members and what are "derived classes" and so on we leave it for discussion later, and now we focus on the first two.
The public type is the type in the example above, which is well understood. The private type, according to the simple explanation in the table, can only be accessed in the class to which the member is declared (that is, the class to which the member belongs), and the bounds are invisible. So, how will members of private type be used? Simply put, it is accessed by means of a public class.
Let's look at a new example:
  
Type
Tdate = Class
Private
Mouth,day,year:integer;
Public
Procedure SetValue (M,d,y:integer);
function Leapyear:boolean;
function gettext:string;
End
  
  
In this class, the three members of the Mouth,day,year are declared as private members, so they are inaccessible anywhere outside the class. In other words, if you use
  
Aday.year: = 2000;
  
This code, then the compiler will error. However, we can still assign values to them by using the SetValue method:
  
Aday.setvalue (1,1,2000);
  
This line of code is legal because SetValue itself is a member of the Tdate class, and it is also a public member. Using the GetText method, you can get the current date value (which is the only way to get the date value of the period).
Such a setting allows some members of the class to be suppressed, and the user can only use them in some specialized way. Those members that can be accessed by external code are called classes of interfaces. What good does it do? First, this allows the author of the class to detect what is being assigned. For example, a user might give an object an invalid date that is 40 days in 1 March. After some of the members are hidden, the author of the class can detect in the code of the method whether the values are valid, thereby greatly reducing the chance of generating errors. Second, using a canonical class, the author can modify the code inside the class at any time, but the code that uses that class does not need any modification! This makes the maintenance of the code an easy event, especially for large software that is collaborative with multiple people.
This is called the Data Encapsulation (encapsulation). This is the first feature of OOP. A good OOP programmer, when designing a class, should determine which important data to encapsulate and give a high-efficiency interface.
One point to note is that the private section of table 1 is perfectly correct for the "standard" OOP language (for example, C + +), but there is an exception to Delphi. In Delphi, private members can be accessed anywhere in the unit (. pas file) where the class is declared, in addition to being accessible in the declaring class, regardless of the relationship of the code to the declaring class. Strictly speaking, this is a violation of OOP principles, I do not understand why Borland to do so (said to be convenient). In the discussion about the merits and demerits of Delphi, this is a problem that is often involved.
  
1.2 Inheritance and derivation
  
Let's take another look at the code:
  
Type
Tnewdate = Class (Tdate)
Public
function gettextnew:string;
End
  
function gettext:string;
Begin
return: = IntToStr (Mouth) + ': ' + inttostr (day) + ': ' + inttostr (year);
End
  
As you can see, there is a class name enclosed in parentheses after class. This syntax means that the new class inherits an old class. The class that inherits the original class is called the derived class, also called the subclass, and the inherited class is called the base class, also called the parent class.
What is the relationship between a derived class and a base class? When a derived class inherits from a base class, it automatically has all the data, methods, and other types of the base class and does not need to be described in the derived class. For example, you can use the Tnewdate class like this code:
  
Var
Aday:tnewdate;
Begin
Aday: = tnewdate.create;
Aday.setvalue (1,1,2000);
If Aday.leapyear Then
ShowMessage (' Leap year: ' + inttostr (aday.year));
Aday.free;
End
  
Also, derived classes can add their own data and methods based on the base class. You can see that a new method gettextnew has been added to the Tnewdate class. Here is a partial implementation of this method:
  
function gettextnew:string;
Begin
return: = GetText;
End
  
Then call it:
  
Aday.gettextnew;
  
This new method works very well.
Why must the Gettextnew method call the GetText method in the base class and not use the code in the GetText method directly? The reason is that the three members of Mouth,day,year are declared as private members, so they cannot be accessed even in derived classes, so you must call the GetText method in the base class to use them indirectly. If you want to use them directly, you can change the properties of these three members from private to protected. As you can see in table 1, the members of the protected property can be accessed in the Declaration class and in the derived classes of the declaring class, but still cannot be accessed by code other than these two cases. Now we can finally understand that this particular attribute actually provides great convenience: it makes the members of the class encapsulated, avoids confusion, and allows derived classes to easily use them.
(If you are a careful person, you may find a small filming leak in the middle of the above words.) When you actually access the private members of the base class in the Gettextnew method, you may be surprised to find that the program can also be compiled and run properly! In fact, this problem is not related to oop itself. As I have said above, in Delphi, private members can be accessed anywhere in the cell file where the class is declared, so it is not surprising if the Tnewdate class and the Tdate class are in the same. pas file. )
What, does it feel so wonderful? Through this inheritance mechanism, the class is no longer just the encapsulation of data and methods, it provides openness. You can easily inherit a powerful class and then add the features you want, and you don't need to make any modifications to the base class. Conversely, any changes that the original author makes to the base class can be immediately reflected in your new class. This is very much in line with code reuse requirements.
This inheritance mechanism is also very much in line with the real world situation. It can be imagined that the general meaning of "animal" is a class, with some of its own characteristics (members), and "dog" is a derived class of "animal", it has all the characteristics of animals, but also has its own unique characteristics (four legs, barking, etc.). and the "dog" class can continue to be derived, such as "Black Dog" "White Dog", which in addition to preserving all the characteristics of the dog, but also has its own characteristics (black color, white color, etc.). And to a living dog, you can think of it as an example of a "black dog" or "White dog" (or any other dog).
This simulation of the real world by OOP not only greatly simplifies the maintenance of the code, but also makes the whole idea of programming revolutionary, and has made a leap forward compared with the modularization programming.
If you have read the VCL data or even its source code, you can see that the entire VCL is built on this powerful encapsulation-inheritance mechanism. You can see a detailed VCL hierarchy chart, which is like a large family tree, and various VCL components are generated through the inheritance of layers. For example, a simple Tform class is the product of many successive inheritance:
Tobject-tpersistent-tconponent-tcontrol-twincontrol-tscrollingwincontrol-tcustomform-tform
Not only Delphi's Vcl,visual C + + 's famous MFC (Microsoft Foundation Class, Microsoft Basic Class Library), and previously Borland C + + in the scene of the Owl (Object Window Library, Object window class library), are built on this mechanism. The difference is that for the first two languages, you have to spend a few months of hard work to master those very complex classes, to write more practical value of the program, and in Delphi, most of the job Delphi has been automatically help you complete. For example, each time you add a form to your program, Delphi automatically derives a new class for you from Tform (default is TForm1) and creates an instance for the new class. Your changes to this form (adding artifacts and code) are nothing more than adding some new features to the derived class; You no longer have to deal with situations such as maximizing, minimizing, resizing, because the code is implemented in the base class and inherited by the derived class. This is the greatness of Delphi. Of course, Delphi's VCL is by no means inferior to MFC or owl (in fact it evolved from the latter).
(Someone may ask about VB.) VB does not support inheritance, so there is no complex class library, its own control is also very poor, mainly the use of ActiveX controls. )。
Perhaps you have been enlightened, for the discovery of your heart itch difficult. But what we're going to talk about is certainly not just that simple.
In part 1.1 ("Data Encapsulation"), we talked about the "create method is an implicit method for every class." In fact, this argument is inaccurate. The fact is that in Delphi, all classes inherit from the most basic class Toject by default, even if you do not specify the inherited class name. The Create method is the method that the TObject class has, so of course, all classes automatically get the Create method, regardless of whether or not you have implemented it. Think about it: if there is no create method, how to create an object?
You may have noticed that the Create method is a special method. Yes, the Create method is really special, even if its "title" is no longer a function or procedure, but a constructor (constructor). You can see some examples in the VCL source code:
  
Constructor Create;
  
The constructor is not only a Delphi keyword, but also a noun of OOP methodology. Corresponding to this, there are also destructor (the destruction of the device). The former is responsible for completing the work of creating an object, allocating memory for it, and the latter responsible for releasing the object and reclaiming its memory. One thing to note is that constructor's name is typically create, but destructor's name is not free, but destroy. For example:
  
destructor Destroy;
  
So, in the previous code, why use free to dispose of objects? The difference is that destroy will directly release the object, and free will actually check if the object exists, and if the object exists, or if the object is not nil, it will call destroy. Therefore, it is safer to use free as much as possible to dispose of objects in the program. (note, however, that free does not automatically set the object to nil, so after you call free, it is better to manually set the object to nil.) )
As with normal functions or procedures, you can also pass parameters to the constructor:
  
Type
Tdate = Class
Private
Mouth,day,year:integer;
Public
function Leapyear:boolean;
function gettext:string;
Constructor Create (M,d,y:integer);
End
  
Procedure Tdate.create (m,d,y): Integer;
Begin
Mouth: = m;
Day: = D;
Year: = y;
End
  
Call it:
  
Aday:tdate;
Begin
Aday: = Tdate.create (1,1,2000);
If Aday.leapyear Then
ShowMessage (' Leap year: ' + inttostr (aday.year));
Aday.free;
End
  
This completes the initialization of the data in the Create method without having to call the SetValue method again.
  
Next, we're going to cover another important and interesting question: the virtual and overloaded methods.
Maybe you've been a little dizzy. Let's start by looking at a new example:
  
Type
Tmyclass = Class
Procedure one;virtual;
End
  
Type
Tnewclass = Class (Tmyclass)
Procedure One;override;
End
  
Procedure tmyclass.one;virtual;
Begin
ShowMessage (' called the Tmyclass Method! ‘);
End
  
Procedure Tnewclass.one; Override
Begin
inherited;
ShowMessage (' called the Tnewclass Method! ‘);
End
  
As you can see, a new class Tnewclass is derived from Tmyclass. All two of these classes declare a method of the same name. The difference is that in tmyclass, a virtual keyword is appended to the one method, indicating that the method is a dummy method. In Tnewclass, an override keyword is appended to the one method, which means that the method is overloaded (override). Heavy-duty technology enables many special functions.
Let's take a closer look at some of their implementation. In the implementation part of the Tmyclass.one method, the call to the showmessage process pops up a dialog box stating that the method has been called; there is no special place here. In the Tnewclass.one method, there is a statement that has never occurred before:
  
inherited;
  
The Chinese meaning of the word is "inheritance". Let's not go into the concept of an OOP that is too complex, as long as you know the function of the statement. Its function is to call the code in the base class in the equivalent virtual method. For example, if you use the following code:
  
Var
Aobject:tnewclass;
Begin
Aobject: = tnewclass.create;
Aobject.one;
Aobject.free;
End
  
Then the program will pop up two dialog boxes, the first time is to call the one method in the Tmyclass class, the second time is the code in the Tnewclass.one method.
Heavy-load technology allows us not only to add the data and methods that the base class does not have in the derived class, but also to easily inherit the code of the original method in the base class, simply by adding inherited. If you do not join the inherited statement, then the corresponding method of the base class will be overwritten by the new method. It must be noted, however, that overloading can only be done if the base class's methods are flagged as virtual, and the overloaded method must have the exact same parameter type as the virtual method.
The virtual method also has a special case, the abstract method:
  
Procedure One;override;abstract;
  
After the one method, there is not only the override keyword, but also an abstract keyword (meaning abstract). This method is called an abstract method (called a pure virtual function in C + +). Classes that contain abstract methods are called abstract classes. The uniqueness of an abstract method is that it only declares, and there is no implementation part, and if you attempt to invoke an abstract method of an object, you will get an exception. It can be called only if the class's derived class overloads and implements the method. (in C + +, you can't even create an instance of an abstract class at all.) )
So what is the use of this abstract approach? This question will be discussed in the next "polymorphic" section.
  
1.3 polymorphic
  
Polymorphism is relatively more complex. But don't worry, its content is relatively small, and if the previous knowledge is more solid, the concept of polymorphism is inevitable.
Let's discuss type compatibility issues first. Here is an example:
  
Type
Tanimal = Class
Procedure voice;virtual;
...
End
  
Tdog = Class (tanimal)
Procedure Voice;override;
...
End
  
Implementation
  
Procedure tanimal.voice;virtual;
Begin
PlaySound (' Anim.wav ', 0,snd_async);
End;
  
Procedure tdog.voice;virtual;
Begin
PlaySound (' Dog.wav ', 0,snd_async);
End;
  
The Tdog class inherits the Tanimal class and overloads the Voice method in it. PlaySound is a win API function that can play the specified WAV file. (The definition of this function can be found in the Mmsystem.pas file.) )
Let's look at this piece of code:
  
Var
MyAnimal1, Myanimal2:tanimal;
Begin
MyAnimal1: = tanimal.create;
MyAnimal2: = tdog.create;
...
  
In the first line of the implementation section, an object of type Tanimal is created and assigned to the variable MyAnimal1 of the Tanimal type. It's a normal thing. In the second row, however, an object of type Tdog is created and given a variable MyAnimal2 of type Tanimal. This may seem surprising, but the code is perfectly legal.
As is known to all, Pascal and Object Pascal are a strict type-defined language, and you cannot assign a value of a type to a variable of a different type, such as assigning an integer value to a Boolean variable, which results in an error. However, there is an important exception to this rule when it comes to the field of OOP: You can assign a subclass's value to a variable of the parent class type. But the upside is no, the value of a parent class must never be assigned to a variable of a subclass type.
If you put this principle into the real world, it is easy to understand that "dogs" inherit from "animals" because dogs are also an animal. So you can give a "dog" type of value to the "animal" type of variable, because "dog" has all the characteristics of "animal". But conversely, "animal" does not have all the characteristics of "dog", so the inverse assignment is not possible.
So what is the use of this compatibility rule in programming?
Please note the following code:
  
Var
MyAnimal1, Myanimal2:tanimal;
Begin
MyAnimal1: = tanimal.create;
MyAnimal2: = tdog.create;
Myanimal1.sound;
Myanimal2.sound;
...
  
Both MyAnimal1 and MyAnimal2 are variables of the tanimal, and both call the sound method. However, the result of execution is completely different: the former executes the Tanimal.voice code, and the latter executes the Tdog.voice code! The reason is simple because MyAnimal1 is given an object of type Tanimal, and MyAnimal2 is given an object of type Tdog. That is, a variable of type tanimal, when it calls the sound method, the code executed is indeterminate: it is possible to execute Tanimal.voice code, or Tdog.voice code, depending on what kind of object it was referencing at that time.
Look again:
  
MyAnimal1: = tanimal.create;
Myanimal1.sound;
Myanimal1.free;
MyAnimal1: = tdog.create;
Myanimal1.sound;
...
  
The same variable MyAnimal1, when the first call to the sound method, executes the Tanimal.voice code, and the second time it executes the Tdog.voice code. Myanimal1.sound This line of code does not need to change, the program can assign different objects to the variable according to different circumstances, so that it executes different code. This is the definition of polymorphism.
This very important feature greatly increases the reusability of the code. As mentioned earlier, simply writing down a line of code allows the program to perform different functions, because this virtual method is compatible with any derived class of tanimal, even those that have not yet been written. Programmers do not need to know the details of these derived classes. The use of polymorphism to write code, but also has a concise and good maintenance characteristics.
Now we can return to the question at the end of section 1.2 of this article. The abstract method itself cannot do anything, it must be overloaded and implemented in subclasses to accomplish meaningful work. The existence of an abstract method, however, is equivalent to leaving an interface for the parent class, and when the program assigns the object of a subclass to a variable of the parent class, the variable of the parent class can invoke the method, which, of course, runs the code that overloads the method in the corresponding subclass. Without this abstract method, a variable of the parent class cannot invoke it because it cannot invoke a method that exists only in the subclass and does not exist in the parent class!
  
This is where the introduction to OOP ends. In these pages, the basic concepts of OOP are introduced, which gives the reader a systematic understanding of OOP and a good basis for the discussion below. More, deeper things await you to discover.
This article has repeatedly emphasized the importance of OOP, and here is one more point: mastery of OOP, in a sense, determines your ability to understand the Delphi world.

Delphi programming OOP thought "turn"

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.