Dúvidas de POO, herança e polimorfismo
03/02/2006
0
1) quando eu devo usar virtual e quando usar dynamic na classe ancestral?
2) quando eu devo usar override na descendente?
3) quando eu devo usar inherited na implementação do método herdado? (atualmente eu uso sempre que desejo executar primeiro a parte original do código da classe pai)
4) quando eu devo usar o reintroduce?
5) quando eu não devo usar override, e caso eu possa modificar métodos assim nos herdeiros, uso o inherited? e se eu quiser mudar os parâmetros?
6) qual a maneira correta, limpa e POO de se criar um método Create para uma classe, descendente de Tobject ou não?
Valew pessoal!
Vitor Rubio
Posts
03/02/2006
Michael
Repostas:
1) [b:98afc038ce]Virtual [/b:98afc038ce]e [b:98afc038ce]dynamic [/b:98afc038ce]têm a mesma função. A diferença é que o primeiro vai gerar um código mais rápido, mas que consome um pouco mais de memória, e o segundo um código que vai utilizar menos memória;
2) [b:98afc038ce]Override [/b:98afc038ce]deve ser usado quando se quer extender ou substituir o código de um método de uma classe ascendente, marcado como [b:98afc038ce]virtual [/b:98afc038ce]ou [b:98afc038ce]dynamic[/b:98afc038ce], por outro;
3) [b:98afc038ce]Inherited [/b:98afc038ce]é usado para acessar o código original de um método marcado como [b:98afc038ce]virtual [/b:98afc038ce]na classe base. Deve ser usado quando há essa necessidade;
4) [b:98afc038ce]Reintroduce [/b:98afc038ce]é uma forma de se sobrescrever um método marcado como [b:98afc038ce]virtual[/b:98afc038ce], mas como parâmetros diferentes do original. Essa palavra-chave só existe para suprimir um warning do compilador para métodos na situação apresentada. Sem ele o código funciona do mesmo jeito, mas vc sempre verá um aviso quando for compilar;
5) As respostas anteriores respondem essa, não? ;-)
6) Bom, isso depende da situação. Se o construtor original estiver marcado como [b:98afc038ce]virtual[/b:98afc038ce], e vc quiser extendê-lo, use [b:98afc038ce]override [/b:98afc038ce]e [b:98afc038ce]inherited[/b:98afc038ce]. Se quiser mudar seus parâmetros, use [b:98afc038ce]reintroduce [/b:98afc038ce]e eventualmente, [b:98afc038ce]inherited[/b:98afc038ce]. Por curiosidade, o que seria uma ´maneira suja´? ;-)
[]´s
03/02/2006
Massuda
type TMinhaClasse = class ... end;
type TMinhaClasse = class(TObject) ... end;
03/02/2006
Vitor Rubio
a mesma coisa vale pra dynamic, certo?
outra coisa: se eu quiser sobrescrever métodos que não foram declarados
com virtual ou dynamic, basta simplesmente redeclarar e usar o inherited caso necessário, mas sem usar o override?
03/02/2006
Massuda
com virtual ou dynamic, basta simplesmente redeclarar e usar o inherited caso necessário, mas sem usar o override?[/quote:f2fc2d9db8]Sim, mas tem uma diferença. Considere isso...
type TPai = class public procedure Proc1; procedure Proc2; virtual; procedure Proc3; end; TFilho = class(TPai) public procedure Proc1; procedure Proc2; override; end; ... procedure TPai.Proc3; begin Proc1; Proc2; end; ...
03/02/2006
Michael
Sim.
[quote:3b1a09f546=´vitor^_^´]outra coisa: se eu quiser sobrescrever métodos que não foram declarados
com virtual ou dynamic, basta simplesmente redeclarar e usar o inherited caso necessário, mas sem usar o override?[/quote:3b1a09f546]
Isso é um pouco complexo de entender, mas acho que com um exemplo fica mais claro:
Usando virtual/dynamic e override:
TCachorro = class procedure Latir; virtual; end; TPitBull = class(TCachorro) procedure Latir; override; end; TPoodle = class(TCachorro) procedure Latir; override; end; ... var Cachorro: TCachorro; begin Cachorro := TPitBull.Create; Cachorro.Latir; // chama TPitBull.Latir Cachorro.Free; Cachorro := TPoodle.Create; Cachorro.Latir; // chama TPoodle.Latir Cachorro.Free; end;
Sem override:
TCachorro = class procedure Latir; virtual; end; TPitBull = class(TCachorro) procedure Latir; end; TPoodle = class(TCachorro) procedure Latir; end; ... var Cachorro: TCachorro; begin Cachorro := TPitBull.Create; Cachorro.Latir; // chama TCachorro.Latir; Cachorro.Free; Cachorro := TPoodle.Create; Cachorro.Latir; // chama TCachorro.Latir; Cachorro.Free; end;
Percebeu a diferença? [b:3b1a09f546]Override [/b:3b1a09f546]é uma maneira de garantir que o método de uma classe será sempre chamado, mesmo que a instância usada seja de um tipo ascendente a ela. É por isso que a mensagem de aviso do Delphi é ´método <nome_método> esconde o método [b:3b1a09f546]virtual [/b:3b1a09f546]da classe base <nome_classe>´. Sem [b:3b1a09f546]override [/b:3b1a09f546]vc pensa que está chamando um código de uma classe, mas na verdade está executando outro, escondido.
Vc sempre pode chamar [b:3b1a09f546]inherited [/b:3b1a09f546]dentro de um método herdado. Deve apenas ter o cuidado de chamar [b:3b1a09f546]inherited [/b:3b1a09f546]NomeDoMetodoOriginal ao invés de só [b:3b1a09f546]inherited [/b:3b1a09f546]caso vc mude a assinatura dele na classe descendente, pois o compilador não será capaz de distinguir um do outro.
Uma última dica: a não ser que o ganho seja real, use sempre [b:3b1a09f546]virtual [/b:3b1a09f546]ao invés de [b:3b1a09f546]dynamic[/b:3b1a09f546]. Um exemplo: ´vc tem uma classe que muitos métodos passíveis de serem sobrescritos (overriden) que são herdados em muitas classes, mas ocasionalmente chamados´ (traduzido do help do Delphi).
[]´s
03/02/2006
Vitor Rubio
Agora uma ironia, pragente rir um pouco: sempre que eu me aventurei a fazer meus programas certinhos, tentando fazer OO, eu usava o virtual e o override da maneira certa, sem querer, porque copiava de exemplos, revistas ou do próprio fonte da VCL. Copiava sem saber direito como funciona.
Criei até alguns componentes assim...
de vez em quando eu esquecia de colocar override num método herdado, de vez em quando eu esquecia de colocar virtual num método ancestral.... e as vezes eu tinha que sobrescrever o método create de algumas forms, usando parâmetros. Devo ter feito muita besteira nesse meio tempo, mas por incrível que pareça tá tudo funcionando. (ou pelo menos ainda não deu uma zica braba) Tô até com medo de mexer agora hauahaua.
03/02/2006
Vitor Rubio
1) pra que serve a palavra reservada [b:bcb6af0e17]object[/b:bcb6af0e17]? pelo que percebi, dá pra criar
estruturas tipo records com ela, mas com métodos, porém, diferentemente das classes, é tudo estático.
2) se as variaveis objetos (instâncias de classes, como edit1) são ponteiros para um local na memória onde está a instância dessse objeto, faz diferença, ao passar esse objeto como parâmetro de uma procedure ou função, usar ou não a palavra reservada [b:bcb6af0e17]var[/b:bcb6af0e17] ? Existe o conceito passar um objeto por valor ou referência?
3) no código fonte da VCL, alguns métodos de componentes estão assim:
procedure tcomponente.blablabla(valor : tipo);
e outros estão assim:
procedure tcomponente.blablabla(const valor : tipo);
qual é a finalidade de passar um parâmetro com a palavra reservada const numa procedure?
valew!!!
03/02/2006
Massuda
estruturas tipo records com ela, mas com métodos, porém, diferentemente das classes, é tudo estático.[/quote:414dfabbd3][b:414dfabbd3]object[/b:414dfabbd3] é uma herança dos tempos do Turbo Pascal. Não é boa idéia usar.
[quote:414dfabbd3=´vitor^_^´]2) se as variaveis objetos (instâncias de classes, como edit1) são ponteiros para um local na memória onde está a instância dessse objeto, faz diferença, ao passar esse objeto como parâmetro de uma procedure ou função, usar ou não a palavra reservada [b:414dfabbd3]var[/b:414dfabbd3] ? Existe o conceito passar um objeto por valor ou referência? [/quote:414dfabbd3]Faz diferença. Quando você passa como [b:414dfabbd3]var[/b:414dfabbd3] singifica que o valor passado está sujeito a ser modificado. No caso, o que será modificado não é o objeto em si, mas sim a referência ao objeto. Por exemplo...
procedure Foo(var Obj: TObject); begin Obj.Free; Obj := nil; end;
[quote:414dfabbd3=´vitor^_^´]...qual é a finalidade de passar um parâmetro com a palavra reservada const numa procedure?[/quote:414dfabbd3][b:414dfabbd3]const[/b:414dfabbd3] nesse contexto é o oposto do [b:414dfabbd3]var[/b:414dfabbd3] que você perguntou antes. Significa que o valor passado não será alterado. Por exemplo...
procedure Foo(const Obj: TObject); begin Obj.Free; Obj := nil; end;
03/02/2006
Michael
1) No Pascal antigo [b:4775e4f666]object [/b:4775e4f666]fazia o papel que [b:4775e4f666]class [/b:4775e4f666]faz hoje. Até o Delphi 2 eu tenho certeza que era suportada ainda, desde que se usasse a notação [b:4775e4f666]System.Object[/b:4775e4f666]. Hoje não sei se ainda é possível fazer isso. De qualque forma não é aconselhado fazer uso dela neste contexto. O uso mais frequente desta palavra reservada é na criação de procedures para serem usadas como ponteiros de eventos:
type MeuEvento = procedure (Sender: TObject; MeuParametro: string) of object;
2) Objetos sempre são passados por referência. [b:4775e4f666]Var [/b:4775e4f666]não influencia em nada (velocidade de acesso, por exemplo), salvo algumas exceções. Isso foi discutido há um tempo atrás aqui. [b:4775e4f666]Massuda[/b:4775e4f666], poste o link, se vc ainda o tiver;
3) A palavra reservada [b:4775e4f666]const [/b:4775e4f666]em parâmetros de procedures/funções impede que o valor deles seja alterado dentro da rotina. Veja:
procedure Teste(const S: string); begin S := ´Teste´; // Erro aqui por causa do const end;
Sem [b:4775e4f666]const [/b:4775e4f666]vc pode alterar o valor do parâmetro localmente. Isso é usado quando vc precisa manter o valor original dentro do procedimento, e quer ter certeza que ele não será alterado, em virtude de esquecimento, por exemplo.
Há uma consideração a ser feita quando se usa [b:4775e4f666]const [/b:4775e4f666]com objetos: vc não vai poder mudar a referência dele, mas pode alterar seus campos e propridades.
procedure Teste(const A: TStringList); var B: TStringList; begin B := TStringList.Create; A := B; // Isso não compila; B.Text := ´Teste´; // Isso sim end;
[]´s
[]´s
03/02/2006
Sourcecode
03/02/2006
Massuda
Outro ex-Borland que hoje trabalha na Microsoft é Chuck Jazdzewski, que chefiou o desenvolvimento do Delphi até a versão 6.
Clique aqui para fazer login e interagir na Comunidade :)