Talk about classes and objects in Delphi
1. Can’t understand several concepts without being educated.
Speaking of classes and objects, we cannot but mention the following concepts: classes, objects, and instances. I personally think it's okay
Understand it this way: object refers to a general term, and any entity in nature can be regarded as an object; while class refers to
A series of categories that are divided into certain characteristics of these objects; an instance refers specifically to an object belonging to a certain category.
Okay, I don’t need to say more about these big principles. Why not take a "contrary" approach, let's use Delphi
code to explain some concepts put forward by these foreigners that are difficult for us Chinese to understand:
var
ABtn:TButton;
Define ABtn as an object belonging to the TButton class, but ABtn cannot be said to be an instance because it has not
is created, so we say that an object is defined. If an instance is defined, more or less
Some are not precise enough. :)
begin
ABtn:=TButton.Create(Self);//Create an instance of TButton
ABtn.Caption:='object';
ABtn.Free;
end;
2. The object is an out-and-out pointer
From a physical point of view, the object is an address space, and the symbol of this address space is what we define.
Class "Variable". So we can think of an object as a pointer to a class. As we all know, to access a pointer, just
The pointer must be initialized. Since the object is a pointer, it must be initialized. How to initialize it?
Let’s talk about the initialization of pointers. There are two ways to initialize a pointer:
(1) Direct distribution
var
Pint:^Integer;
begin
new(Pint);
Pint^:=12;
Dispose(Pint);
end;
(2) Variables pointing to other allocated spaces
var
Pint:^Integer;
i:integer;
begin
i:=12;
Pint:=@i;
end;
Interestingly, there are two ways to initialize "pointers" like objects:
(1) Direct distribution
var
AForm:TForm;
begin
AForm:=TForm.Create(Self);
AForm.ShowModal;
AForm.Free;
end;
(2) Point to other instances of allocated space
var
AForm:TForm;
begin
AForm:=Self;
AForm.Caption:='Do you know? Why is this happening';
end;
file://This AForm and the Form instance it points to share the same address unit, and all operations on the AForm will respond
file:// to its corresponding Form instance.
Speaking of which, we can easily explain why the object parameters of the procedure (function) are passed in a format like this:
(1)PRocedure SetEdit(var Edit:TEdit);
begin
Edit.Text:='11';
end;
and
(2) procedure SetEdit(Edit:TEdit);
begin
Edit.Text:='11';
end;
The effect is the same. (1) is to pass a TEdit entity as a parameter reference, (2) is
Pass a TEdit object "pointer" as a parameter.
3. Class can be understood as a special data type
We know that data types can be forced to type conversion. Since a class can be understood as a data type, then
Then it should also be able to perform class type conversion. For example, the following code is a click event of a button (Button1):
(one)
procedure TForm1.Button1Click(Sender: TObject);
var
ACaption:String;
begin
ACaption:=TButton(Sender).Caption;//Sender converts from TObject to TButton
ShowMessage(Format('You clicked ''%s'' !',[ACaption]));
end;
In this code, Sender is a TObject type object, and we cast it to TButton type. like you
If you can’t see clearly, you can refer to our usual data type conversion:
(two)
procedure TForm1.Button1Click(Sender: TObject);
var
S_Str:String;
P_Str:PChar;
begin
S_Str:='I love China!';
P_Str:=PChar(S_Str);
S_Str:='';
S_Str:=String(P_Str);
ShowMessage(S_Str);
end;
However, in the process of object-oriented programming, the emphasis is on safety. For example, the forced type conversion in (1) has many problems.
Security. The following code still writes the Button1.OnClick event:
(three)
procedure TForm1.Button1Click(Sender: TObject);
begin
TCanvas(Sender).Brush.Color:=clRed;
end;
If you execute it, an error will occur. Doesn't this violate the purpose of object-oriented programming? No, of course
If it is a class, there should be a class-specific class coercion method. The method to change (3) is as follows:
(Four)
procedure TForm1.Button1Click(Sender: TObject);
begin
(Sender as TCanvas).Brush.Color:=clRed;
end;//Use as to convert, as can catch the error and will not affect the normal operation of the program.
Speaking of which, let me mention VB by the way. If you have learned VB, you may find the control array in it more enjoyable, especially in
When writing a program like a calculator. But what does Delphi give us? The answer is that Delphi can also be opened quickly and concisely.
Issue such a program. If you do this: put an Edit and ten Buttons on the form, divide Button.Caption into
Don't set it to '0', '1', '2',...'9', and then write the OnClick event of a button as follows:
(five)
procedure TForm1.Button1Click(Sender: TObject);
begin
Edit1.Text:=Edit1.Text+(Sender as TButton).Caption;
end;
Associate the OnClick events of other Buttons to Button1Click and run the program. Clap your hands! This calculator
The prototype of the program is now available. We use Delphi's class type conversion to develop a control array function similar to that in VB.
The program is also great! :)
4. Abstract class and its instances
There is a class in Delphi called an abstract class, and you cannot naively create an instance of it directly. Such as: TStrings
kind. The following code:
(one)
var
StrLst:TStrings;
begin
StrLst:=TStrings.Create;
StrLst.Add('I love Japan!');
StrLst.Free;
end;
This is not right. So how do you construct instances of abstract classes like TStrings? The answer is to use its non-pumping
Elephant subclass. We know that TStrings has a non-abstract subclass of TStringList. We can do this:
(two)
var
StrLst:TStrings;
begin
StrLst:=TStringList.Create;//Subclass StrLst with the help of its subclass constructor
StrLst.Add('I love China!');
StrLst.Free;
end;
(three)
var
StrLst:TStringList;
begin
StrLst:=TStringList.Create;
file://Give up, don't use abstract classes anymore, just use its "son" to do your business
StrLst.Add('I love China!');
StrLst.Free;
end;
5. Classes are a highly encapsulating mechanism for data and operations.
(1) Data encapsulation
unit Unit2;
interface
type
TEmployee=class
private
FName:String;
public
Constructor Create;
function GetName:String;
procedure SetName(AName:String);
end;
implementation
{ Employee }
constructor TEmployee.Create;
begin
FName:='BlazingFire';
end;
function TEmployee.GetName: String;
begin
Result:=FName;
end;
procedure TEmployee.SetName(AName: String);
begin
FName:=AName;
end;
end.
As shown in the code above, we use a procedure SetName and a function GetName to completely set the private variable FName.
Encapsulation. This is all we need to do with FName:
uses
unit2;
procedure TForm1.Button1Click(Sender: TObject);
var
AEmployee:TEmployee;
begin
AEmployee:=TEmployee.Create;
AEmployee.SetName('Rose');//Use SetName to set FName
MessageBox(Handle,PChar(AEmployee.GetName),'Empoyee',0);
file://Use GetName to access FName
AEmployee.Free;
end;
(2) Operation encapsulation
unit Unit2;
interface
type
TDivision=Class
public
file://polymorphism makes your program more "flexible"
function GetDiv(Num1,Num2:Double):Double;overload;
function GetDiv(Num1,Num2:integer):integer;overload;
end;
implementation
{ Division }
function TDivision.GetDiv(Num1, Num2: Double): Double;
begin
try
Result:=Num1/Num2;
except
Result:=0;//Provides a bullet processing mechanism to handle the situation where the divisor is 0
end;
end;
function TDivision.GetDiv(Num1, Num2: integer): integer;
begin
try
Result:=Num1 div Num2;
except
Result:=0;//Provides a bullet processing mechanism to handle the situation where the divisor is 0
end;
end;
end.
In the above code, we use the polymorphism mechanism of the class to process the division into integer division and non-integer division respectively, and use the exception handling screen
To remove the case where the number is 0, to ensure the safety of the operation, when calling, we can do it like this:
uses
unit2;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
Division:TDivision;
IValue:integer;
FValue:Double;
begin
Division:=TDivision.Create;
IValue:=Division.GetDiv(1,2);
FValue:=Division.GetDiv(1.0,2);
IValue:=Division.GetDiv(1,0);
FValue:=Division.GetDiv(1.0,0);
Division.Free;
end;
6. Classes are a code reuse mechanism
For example, in 5, if we want to add a GetAdd function to this class to perform addition operations, we can use class inheritance. like
Just write:
(one)
unit Unit2;
interface
type
TDivision=Class
public
function GetDiv(Num1,Num2:Double):Double;overload;
function GetDiv(Num1,Num2:integer):integer;overload;
end;
type
TOperation=Class(TDivision)
public
function GetAdd(Num1,Num2:Double):Double;
end;
implementation
{ Division }
function TDivision.GetDiv(Num1, Num2: Double): Double;
begin
try
Result:=Num1/Num2;
except
Result:=0;
end;
end;
function TDivision.GetDiv(Num1, Num2: integer): integer;
begin
try
Result:=Num1 div Num2;
except
Result:=0;
end;
end;
{TOPperation}
function TOperation.GetAdd(Num1, Num2: Double): Double;
begin
Result:=Num1+Num2;
end;
end.
Here we inherit a subclass TOPeration from TDivision. TOperation can have TDivsion
The public method GetDiv has its own unique method GetAdd. This is the "have your cake and eat it too" class provides us.
"Get" method. Not bad. :)