Jump to content
thoga31

Problemas com Property's

Recommended Posts

thoga31

Ora, agora sou eu que tenho uma dúvida... Já fazia tempo... :D

Ando nas minhas experiências com classes, e estou a entrar na história das propriedades. Acostumado ao POO do VB.NET, o POO do Delphi é-me diferente aka estranho e a little bit stupid (ai o @nuno que me excomunga :knuppel2:).

Consegui que o seguinte código fosse compilado,m mas dá-me o erro de execução nº 217 (whatever it means...).

Mais, suponho que haja forma de definir a propriedade Angle sem ter de recorrer ao InAng mas fazendo Angle := valor (nas linhas realçadas).

{$mode DELPHI}

PROGRAM EX_CLASSES;
USES CRT, MATH;

TYPE CAngle = class
             private
               //Ang : real;
               procedure InAng(value : real);
               function OutAng : real;

             public
               function Rad2Deg(const rad : real) : real;
               function Deg2Rad(const deg : real) : real;
               property Angle : real read OutAng write InAng;
               constructor Create;
     end;

VAR Angulo : CAngle;
    Num: real;


FUNCTION CAngle.OutAng : real;
BEGIN
     result := Angle;
END;


CONSTRUCTOR CAngle.Create;
BEGIN
     Angle := 0;
END;


PROCEDURE CAngle.InAng(value : real);
BEGIN
     Angle := value;
END;


FUNCTION CAngle.Rad2Deg(const rad : real) : real;
BEGIN
     result := (rad*180)/pi;
END;


FUNCTION CAngle.Deg2Rad(const deg : real) : real;
BEGIN
     result := (deg*pi)/180;
END;


BEGIN
     write('Angulo em graus? ');
     readln(num);
     with Angulo do begin
          Create;
          InAng(Num);
          writeln(Angle:0:5,' graus em radianos: ',Deg2Rad(Angle):0:5);
          writeln('Teste da conversÆo de cancelamento: ',Rad2Deg(Deg2Rad(Angle)):0:5);
     end;
     readln; // pausa
END.

Cumprimentos. ;)

P.S. - yah yah, não comentei este programa :cheesygrin:


Knowledge is free!

Share this post


Link to post
Share on other sites
nunopicado

Olha o tau-tau miudo...  :cheesygrin:

Então vai assim:

O constructor não pode estar dentro do WITH, pelo facto de que a variavel Angulo é nil antes de ser chamado o create, pelo que não tem ainda método algum.

Pelo mesmo motivo, não podes chamar simplesmente assim:

Angulo.create;  // Isto dá erro

A maneira correcta de inicializar uma classe em Delphi é:

Angulo:=CAngle.create;  // atribuis à variável Angulo o resultado do CONSTRUCTOR da classe.

A partir daqui, já podes colocar o resto dentro do WITH, assim:

Angulo:=CAngle.Create;
     with Angulo do begin

          InAng(Num);

          writeln(Angle:0:5,' graus em radianos: ',Deg2Rad(Angle):0:5);
          writeln('Teste da conversão de cancelamento: ',Rad2Deg(Deg2Rad(Angle)):0:5);
     end;
     Angulo.Free;  // Deves sempre correr o DESTRUCTOR da classe quando deixas de a usar, para libertar a memoria...
     // Aqui já podes correr directamente da variável Angulo, pois a classe já está atribuida nesta variável

Isto tras-nos agora a outro problema...

Não estou a ver para que queres neste caso a propriedade... Se as funções conversoras são publicas... Ou estou a ver mal a coisa?


"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Share this post


Link to post
Share on other sites
nunopicado

Estava a ver melhor o teu código e reparei que me passaram alguns... pormenores!  :cheesygrin:

Os procedimentos InAng e OutAng realmente não são necessários. Primeiro porque os estás a usar mal, segundo o conceito de classes:

Visto que é um procedimento PRIVATE, nunca o poderias usar no corpo principal. No caso, só o conseguiste, porque "dobraste" as leis de Object Pascal, e criaste a classe dentro do programa.

NOTA1: 1 Classe = 1 Unit - É esta a regra para poder haver segurança

Independentemente disto, para um teste, é quanto basta, desde que tenhas a noção de que todos os elementos da classe, sejam private ou public, ficam disponiveis para todo o programa, pois essa segurança refere-não se aplica ao namespace à qual a classe pertence, ou seja, a propria unit ou programa.

Ponto 2:

As funções Deg2Rad e Rad2Deg, sendo publicas e aceitando parametros, tornam inuteis as propriedades. Aliás, tornam inútil até o uso da classe.

Mas como eu sei que aqui o que te interessa não é propriamente as funções, mas sim o uso da classe, sugiro-te o seguinte:

As funções passam a ser privadas, e deixas publico apenas as propriedades e o constructor.

Ainda sugiro outra coisa:

Usas o constructor e / ou uma propriedade para definir o angulo, e depois duas propriedades só de leitura para fazer o interface com as funções de conversão.

Do tipo:

Para o seguinte programa principal, desenvolve uma classe:

BEGIN
     Angulo:=CAngle.Create;
     with Angulo do
          repeat
                write('Angulo a converter? ');
                readln(num);
                Angle:=Num;
                writeln('Valor Inserido: ',Angle:0:5);
                writeln('      em Graus: ',Graus:0:5);
                writeln('   em Radianos: ',Radianos:0:5);
                writeln;
                writeln('         Teste: ',Test:0:5);
                writeln;
          until Num=0;
     Angulo.Free;
     delay(1000); // pausa
END.

NOTA: A classe deverá permitir que o angulo seja inserido também no momento da criação, e não apenas através da propriedade Angle...

(Esta é só para teres oportunidade de usar uma coisa que gostas muito... heheheh)


"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Share this post


Link to post
Share on other sites
thoga31

Agora estou no PC de uma amiga minha, e não tenho o FPC aqui (claro) - só o youtube a cantar o Pintainho Piu... Enfim...

Obrigado desde já pela resposta. Eu já tinha falado um pouco com o @pedro-kun e já tinha corrigido algumas coisas, mas estou a ver que tenho MUITO para aprender... :cheesygrin:

E desculpa lá qualquer coisinha, mas em VB.NET as propriedades são very good nice sim sinhor :D

Public Class CAngulo

Public Sub New(Byval value As Double)
    Ang = value  ' ou ang ou angulo, só vendo e testando esta linha xD
End Sub

Dim Ang As Double
Public Property Angulo As Double
    Set(ByVal value As Double)
        Ang = value
    End Set
    Get
        Return Ang
    End Get
End Property

End Class

'...

Public Angulo As New CAngulo(0)

E não falha, eheh :)

Cumprimentos. ;)


Knowledge is free!

Share this post


Link to post
Share on other sites
nunopicado

Como eu te disse ontem, antes de saber, tudo é complicado... :cheesygrin:

Estava aqui a olhar para a versão VB.net, e a pensar: Eh pá, não precisavam complicar tanto! lol

É tudo uma questão de hábito!

Entretanto vou por só uma pequena alteração no "desafio", que é uma função para testar a conversão (ou seja, o resultado das duas contas tem de ser sempre igual ao angulo inserido) para simular o teu uso das duas funções no programa principal.

Já agora, um pormenor (que não é mais que isso, pois não é obrigatório para funcionar):

Em Delphi (e acho que não só) convencionou-se que as definições das classes comecem por T. No teu caso, em vez de CAngle, seria algo tipo TAngleConverter ou coisa parecida.

Mas lá está, isto é apenas uma convenção para facilitar a leitura por parte dos humanos, o compilador não passa cartão a isto...

Tenta lá então fazer uma classe para o programa acima, e depois mostra aí... ;)


"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Share this post


Link to post
Share on other sites
thoga31

Fazer a classe, só amanhã :cheesygrin:

Eu sei que quando aprender será fixe. E eu utilizo C de Classe, e para os tipos é que faço T, de Type ;)


Knowledge is free!

Share this post


Link to post
Share on other sites
nunopicado

lol Pensei que o C de CAngle era algo tipo ConverterAngle abreviado... hehehehe

Amanhã também é dia! :cheesygrin:


"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Share this post


Link to post
Share on other sites
pwseo

Aqui fica um exemplo funcional e comentado, por falta de paciência para um post mais longo.

Acrescento apenas que as variáveis a e b no meu código são na verdade apontadores para instâncias da classe TAngle, daí a necessidade de fazer a := TAngle.Create;, uma vz que o construtor é na realidade uma função que aloca um bloco de memória e devolve o seu endereço. Sem isso, a ou b continuam nil (que é quase um sinónimo para "inexistentes").

{$mode objfpc}
program thoga;

uses
  Math;

type
  TAngle = class
  private
    (* Aqui guardamos o campo ao qual vamos mais tarde
       aceder através da propriedade 'Angle' *)
    FAngle: real;
    (* Só precisamos de setAngle, uma vez que a leitura
       da propriedade só nos devolve o valor de 'FAngle' *)
    procedure setAngle(v: real);
  public
    (* É-nos muito conveniente ter dois construtores *)
    constructor Create; overload;
    constructor Create(v: real); overload;
    (* Cá está: ler de 'FAngle' e escrever via 'setAngle' *)
    property Angle: real read FAngle write setAngle;
  end;

procedure TAngle.setAngle(v: real);
begin
  (* uma vez que não podemos fazer x mod 360 sendo
     x um real, fiz a conta de outra forma *)
  self.FAngle := v - (floor(v / 360) * 360)
end;

constructor TAngle.Create;
begin
  (* Isto é importante; invoca o construtor da
     classe ascendente (TObject, neste caso) *)
  inherited Create;
  self.Angle := 0;
end;

constructor TAngle.Create(v: real);
begin
  inherited Create;
  (* Usamos a nossa propriedade para fazer wrap-around dos valores! *)
  self.Angle := v;
end;

var
  a, b: TAngle;
begin
  a := TAngle.Create;
  (* A parte bonita é que o nosso código vai transformar aquele 402
     em 42 porque definimos a property 'Angle' *)
  b := TAngle.Create(402); 
  writeln(a.angle:0:2);
  writeln(b.angle:0:2);
  a.Free;
  b.Free;
end.

Aqui fica compilado e executado: http://ideone.com/DOTVm

Share this post


Link to post
Share on other sites
thoga31

Amanhã verei isso com mais calma, que eu não compreendo isso do self e etc... :cheesygrin:

Só me apetece perguntar wth?

Até amanhã, abraço, e obrigado por tudo até agora. ;)


Knowledge is free!

Share this post


Link to post
Share on other sites
pwseo

A variável self é essencialmente a instância do objecto com o qual estás a lidar.

Eu uso ali sem grande necessidade, mas é uma boa prática para evitar ambiguidades. Imagina que existia uma variável fora da classe com o nome FAngle, o compilador poderia referir-se a uma que não fosse a que tu queres; com a utilização de self sabes que te referes à variável do objecto.

É a mesma coisa que a variável this noutras linguagens.

Share this post


Link to post
Share on other sites
thoga31

A variável self é essencialmente a instância do objecto com o qual estás a lidar.

Eu uso ali sem grande necessidade, mas é uma boa prática para evitar ambiguidades. Imagina que existia uma variável fora da classe com o nome FAngle, o compilador poderia referir-se a uma que não fosse a que tu queres; com a utilização de self sabes que te referes à variável do objecto.

É a mesma coisa que a variável this noutras linguagens.

Java power e.g. ;)

Estou naquela de vou-me embora, mas aqui os mans estão à espera que as donzelas se arranjem todas, eheheh :cheesygrin:  (não, elas não estão a ler isto)


Knowledge is free!

Share this post


Link to post
Share on other sites
nunopicado

Então Thoga, já fizeste o exercício?  :thumbsup:


"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Share this post


Link to post
Share on other sites
thoga31

Então Thoga, já fizeste o exercício?  B)

Calma lá que só agora começaram as férias :thumbsup:

E mesmo assim tenho já montes de trabalhos e relatórios para o Natal - é a única prenda que os profs sabem dar... Enfim...


Knowledge is free!

Share this post


Link to post
Share on other sites
nunopicado

Atão... Não queres ser médico?

Tens de estudar pá! hehehe


"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Share this post


Link to post
Share on other sites
thoga31

Atão... Não queres ser médico?

Tens de estudar pá! hehehe

Médico não sou eu, é quem tu sabes (não digo já que não sei se a dita pessoa quer que se saiba :thumbsup: )


Knowledge is free!

Share this post


Link to post
Share on other sites
thoga31

Pronto, já aprendi como isto funciona! :thumbsup:

Obrigado a ambos! B)

{$mode delphi}

program OOP_Test;

type TAngle = class
              private
              (* Visível só para a classe *)
                     AngleValue : real;  // Valor do ângulo (a propriedade deve ter algo, por si só não é nada)
                     procedure SetAngle(const Ang : real); // Para escrever na Property

              public
              (* Visível para todo o programa *)
                    constructor Create(const Ang : real);  // "Criação" da classe
                    property Angle : real read AngleValue write SetAngle;  // Valor do ângulo (propriedade)

     end;

var Angulo : TAngle;  // classe de teste
    Num : real;       // valor introduzido pelo utilizador


constructor TAngle.Create(const Ang : real);
(*  CONSTRUTOR  *)
begin
     inherited Create;  // Invoca construtor da classe ascendente TObject
     self.Angle := Ang; // Define propriedade com o valor pretendido
end;

procedure TAngle.SetAngle(const Ang : real);
(*  LER PROPRIEDADE "ANGLE"  *)
begin
     self.AngleValue := Ang - (round(Ang / 360) * 360);
     // ângulo principal de um ângulo (>-180º e <=180º)
end;


begin
     write('Introduza angulo em graus: ');
     readln(Num);
     Angulo := TAngle.Create(Num);  // cria a classe logo com o valor pretendido
     writeln('Angulo principal: ', Angulo.Angle:0:3);  // devolve propriedade "angle"
     readln;  // pausa
end.

http://ideone.com/0OHkm

NOTA: no link está "uses math", mas tal é desnecessário! Foi falha da minha parte... B)


Knowledge is free!

Share this post


Link to post
Share on other sites
pwseo

O estudante de Medicina sou eu :P no 6º ano.

Quando ao código, agora sim está bem.

É de reforçar o facto de que para utilizar propriedades não precisamos de ter métodos para definir e para ler a propriedade; Neste caso, como é  óbvio, basta-nos ter o método para definir, visto que a leitura não altera em nada o valor armazenado. (por vezes as pessoas fazem getters e setters desnecessários).

Outra coisa: boa ideia utilizar o ideone :)

Share this post


Link to post
Share on other sites
thoga31

Outra coisa: boa ideia utilizar o ideone B)

Sempre se pode testar sem que o pessoal tenha de compilar. Testam-se vários inputs, e finito. B)

Obrigado, mais uma vez. Já fazia falta saber mais OOP em Object Pascal / Delphi. :thumbsup:


Knowledge is free!

Share this post


Link to post
Share on other sites
nunopicado
:)   ;)

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.