Fale sobre classes e objetos em Delphi
1. Não consigo entender vários conceitos sem ser educado.
Falando em classes e objetos, não podemos deixar de mencionar os seguintes conceitos: classes, objetos e instâncias. Eu pessoalmente acho que está tudo bem
Entenda desta forma: objeto refere-se a um termo geral, e qualquer entidade na natureza pode ser considerada um objeto enquanto classe se refere a;
Uma série de categorias que se dividem em determinadas características desses objetos; uma instância refere-se especificamente a um objeto pertencente a uma determinada categoria;
Ok, não preciso dizer mais nada sobre esses grandes princípios. Por que não adotar uma abordagem "contrária", vamos usar Delphi
código para explicar alguns conceitos apresentados por esses estrangeiros que são difíceis de entender para nós, chineses:
var
ABtn:TBotão;
Defina ABtn como um objeto pertencente à classe TButton, mas ABtn não pode ser considerado uma instância porque não foi
é criado, então dizemos que um objeto está definido. Se uma instância for definida, mais ou menos.
Alguns não são suficientemente precisos. :)
começar
ABtn:=TButton.Create(Self);//Cria uma instância de TButton
ABtn.Caption:='objeto';
ABtn.Grátis;
fim;
2. O objeto é um ponteiro completo
Do ponto de vista físico, o objeto é um espaço de endereçamento, e o símbolo desse espaço de endereçamento é o que definimos.
Classe "Variável". Portanto, podemos pensar em um objeto como um ponteiro para uma classe. Como todos sabemos, para acessar um ponteiro, basta
O ponteiro deve ser inicializado. Como o objeto é um ponteiro, ele deve ser inicializado. Como inicializá-lo?
Vamos falar sobre a inicialização de ponteiros. Existem duas maneiras de inicializar um ponteiro:
(1) Distribuição direta
var
Pinta:^Inteiro;
começar
novo(Pinta);
Pinta^:=12;
Descartar(Quatro);
fim;
(2) Variáveis que apontam para outros espaços alocados
var
Pinta:^Inteiro;
eu: inteiro;
começar
eu:=12;
Pinta:=@i;
fim;
Curiosamente, existem duas maneiras de inicializar "ponteiros" como objetos:
(1) Distribuição direta
var
AFormulário:TFormulário;
começar
AForm:=TForm.Create(Self);
AForm.ShowModal;
AForm.Free;
fim;
(2) Apontar para outras instâncias de espaço alocado
var
AFormulário:TFormulário;
começar
AFormulário:=Próprio;
AForm.Caption:='Você sabe? Por que isso está acontecendo?
fim;
file://Este AForm e a instância do Form apontam para compartilhar a mesma unidade de endereço, e todas as operações no AForm responderão
file:// para sua instância de formulário correspondente.
Falando nisso, podemos facilmente explicar porque os parâmetros do objeto do procedimento (função) são passados em um formato como este:
(1)PRocedure SetEdit(var Edit:TEdit);
começar
Editar.Texto:='11';
fim;
e
(2) procedimento SetEdit(Edit:TEdit);
começar
Editar.Texto:='11';
fim;
O efeito é o mesmo. (1) é passar uma entidade TEdit como referência de parâmetro, (2) é
Passe um "ponteiro" do objeto TEdit como parâmetro.
3. Classe pode ser entendida como um tipo de dados especial
Sabemos que os tipos de dados podem ser forçados à conversão de tipo. Como uma classe pode ser entendida como um tipo de dados, então.
Então ele também deverá ser capaz de realizar a conversão do tipo de classe. Por exemplo, o código a seguir é um evento de clique de um botão (Button1):
(um)
procedimento TForm1.Button1Click(Remetente: TObject);
var
AClegenda:String;
começar
ACaption:=TButton(Sender).Caption;//Sender converte de TObject para TButton
ShowMessage(Format('Você clicou em ''%s'' !',[ACaption]));
fim;
Neste código, Sender é um objeto do tipo TObject e o convertemos para o tipo TButton. como você
Se você não consegue ver claramente, pode consultar nossa conversão usual de tipo de dados:
(dois)
procedimento TForm1.Button1Click(Remetente: TObject);
var
S_Str:Sequência;
P_Str:PChar;
começar
S_Str:='Eu amo a China!';
P_Str:=PChar(S_Str);
S_Str:='';
S_Str:=String(P_Str);
ShowMessage(S_Str);
fim;
No entanto, no processo de programação orientada a objetos, a ênfase está na segurança. Por exemplo, a conversão forçada de tipo em (1) apresenta muitos problemas.
Segurança. O código a seguir ainda grava o evento Button1.OnClick:
(três)
procedimento TForm1.Button1Click(Remetente: TObject);
começar
TCanvas(Sender).Brush.Color:=clRed;
fim;
Se você executá-lo, ocorrerá um erro. Isso não viola o propósito da programação orientada a objetos? Não, claro
Se for uma classe, deve haver um método de coerção de classe específico da classe. O método a ser alterado (3) é o seguinte:
(Quatro)
procedimento TForm1.Button1Click(Remetente: TObject);
começar
(Remetente como TCanvas).Brush.Color:=clRed;
end;//Use as para converter, pois pode detectar o erro e não afetará o funcionamento normal do programa.
Falando nisso, a propósito, deixe-me mencionar VB. Se você aprendeu VB, poderá achar o array de controle mais agradável, especialmente em.
Ao escrever um programa como uma calculadora. Mas o que o Delphi nos dá? A resposta é que o Delphi também pode ser aberto de forma rápida e concisa.
Emita tal programa. Se você fizer isso: coloque um Edit e dez Buttons no formulário, divida Button.Caption em
Não defina-o como '0', '1', '2',...'9' e, em seguida, escreva o evento OnClick de um botão da seguinte maneira:
(cinco)
procedimento TForm1.Button1Click(Remetente: TObject);
começar
Edit1.Text:=Edit1.Text+(Remetente como TButton).Caption;
fim;
Associe os eventos OnClick de outros Buttons ao Button1Click e execute o programa. Bata palmas!
O protótipo do programa já está disponível. Usamos a conversão de tipo de classe do Delphi para desenvolver uma função de array de controle semelhante à do VB.
O programa também é ótimo :)
4. Classe abstrata e suas instâncias
Existe uma classe no Delphi chamada classe abstrata e você não pode criar ingenuamente uma instância dela diretamente. Como: TStrings
tipo. O seguinte código:
(um)
var
StrLst:TStrings;
começar
StrLst:=TStrings.Create;
StrLst.Add('Eu amo o Japão!');
StrLst.Free;
fim;
Isso não está certo. Então, como você constrói instâncias de classes abstratas como TStrings? A resposta é usar seu não bombeamento
Subclasse de elefante. Sabemos que TStrings possui uma subclasse não abstrata de TStringList. Podemos fazer isso:
(dois)
var
StrLst:TStrings;
começar
StrLst:=TStringList.Create;//Subclasse StrLst com a ajuda de seu construtor de subclasse
StrLst.Add('Eu amo a China!');
StrLst.Free;
fim;
(três)
var
StrLst:TStringList;
começar
StrLst:=TStringList.Create;
file://Desista, não use mais classes abstratas, apenas use seu "filho" para fazer seus negócios
StrLst.Add('Eu amo a China!');
StrLst.Free;
fim;
5. As classes são um mecanismo altamente encapsulante para dados e operações.
(1) Encapsulamento de dados
unidade Unidade2;
interface
tipo
TEFuncionário = turma
privado
NomeF:String;
público
Construtor Criar;
função GetNome:String;
procedimento SetNome(ANome:String);
fim;
implementação
{ Funcionário }
construtor TEmployee.Create;
começar
FName:='Fogo Ardente';
fim;
função TEmployee.GetName: String;
começar
Resultado:=FNome;
fim;
procedimento TEmployee.SetName(AName: String);
começar
FNome:=ANome;
fim;
fim.
Conforme mostrado no código acima, usamos um procedimento SetName e uma função GetName para definir completamente a variável privada FName.
Encapsulamento. Isso é tudo que precisamos fazer com FName:
usa
unidade2;
procedimento TForm1.Button1Click(Remetente: TObject);
var
AFuncionário:TEFuncionário;
começar
AEmployee:=TEmployee.Create;
AEmployee.SetName('Rose');//Use SetName para definir FName
MessageBox(Handle,PChar(AEmployee.GetName),'Funcionário',0);
file://Use GetName para acessar FName
AFuncionário.Grátis;
fim;
(2) Encapsulamento de operação
unidade Unidade2;
interface
tipo
DivisãoT=Classe
público
file://polimorfismo torna seu programa mais "flexível"
function GetDiv(Num1,Num2:Double):Double;sobrecarga;
function GetDiv(Num1,Num2:inteiro):inteiro;sobrecarga;
fim;
implementação
{Divisão}
função TDivision.GetDiv(Num1, Num2: Duplo): Duplo;
começar
tentar
Resultado:=Num1/Num2;
exceto
Resultado:=0;//Fornece um mecanismo de processamento de marcadores para lidar com a situação em que o divisor é 0
fim;
fim;
função TDivision.GetDiv(Num1, Num2: inteiro): inteiro;
começar
tentar
Resultado:=Num1 div Num2;
exceto
Resultado:=0;//Fornece um mecanismo de processamento de marcadores para lidar com a situação em que o divisor é 0
fim;
fim;
fim.
No código acima, usamos o mecanismo de polimorfismo da classe para processar a divisão em divisão inteira e divisão não inteira, respectivamente, e usamos a tela de tratamento de exceções
Para retirar o caso em que o número é 0, para garantir a segurança da operação, no momento da chamada podemos fazer assim:
usa
unidade2;
{$R *.dfm}
procedimento TForm1.Button1Click(Remetente: TObject);
var
Divisão: Divisão T;
ValorI:inteiro;
ValorF:Duplo;
começar
Divisão:=TDivision.Create;
IValor:=Divisão.GetDiv(1,2);
FValue:=Divisão.GetDiv(1.0,2);
IValue:=Divisão.GetDiv(1,0);
FValue:=Divisão.GetDiv(1.0,0);
Divisão.Livre;
fim;
6. As classes são um mecanismo de reutilização de código
Por exemplo, em 5, se quisermos adicionar uma função GetAdd a esta classe para realizar operações de adição, podemos usar herança de classe. como
Basta escrever:
(um)
unidade Unidade2;
interface
tipo
DivisãoT=Classe
público
function GetDiv(Num1,Num2:Double):Double;sobrecarga;
function GetDiv(Num1,Num2:inteiro):inteiro;sobrecarga;
fim;
tipo
TOoperação=Classe(TDivisão)
público
função GetAdd(Num1,Num2:Duplo):Duplo;
fim;
implementação
{Divisão}
função TDivision.GetDiv(Num1, Num2: Duplo): Duplo;
começar
tentar
Resultado:=Num1/Num2;
exceto
Resultado:=0;
fim;
fim;
função TDivision.GetDiv(Num1, Num2: inteiro): inteiro;
começar
tentar
Resultado:=Num1 div Num2;
exceto
Resultado:=0;
fim;
fim;
{TOPoperação}
função TOoperation.GetAdd (Num1, Num2: Duplo): Duplo;
começar
Resultado:=Num1+Num2;
fim;
fim.
Aqui herdamos uma subclasse TOPeration de TDivision. A operação pode ter TDivsion
O método público GetDiv possui seu próprio método GetAdd. Essa é a aula “coma seu bolo e coma também” que nos proporciona.
Método "Obter". Nada mal.