Clipper On Line • Ver Tópico - Montar Array de Objetos no Harbour

Montar Array de Objetos no Harbour

Projeto Harbour - Compilador de código aberto compatível com o Clipper.

Moderador: Moderadores

 

Montar Array de Objetos no Harbour

Mensagempor Cavalo Marinho » 19 Jul 2017 08:54

Bom dia Pessoal, Solicito ajuda dos mestres para solucionar esta questão
Estou desenvolvendo uma aplicação com uma boa parte em orientação a objeto, acontece que eu nao consigo fazer um array de objeto, estou postando uma pequena parte do código para melhor esclarecer:
O que Acontece: faço um loop na tabela e preencho o objeto, até aí tudo certo, pego este objeto e adiciono a lista criada, o problema é que quando vou ler a lista ela está toda preenchida com o ultimo objeto lido, ou seja preencho tudo certinho mas nao sei por que ao ir adicionando mais um objeto esta lista atualiza todos os seus itens com este ultimo objeto:
Exemplo: Li o primeiro JOSE DOS SANTOS, adicionei a lista, pra conferir mandei exibir tudo ok, li o segundo JOSE OLIVEIRA adicionei a lista, mandei exibir e aí os dois itens da lista está com JOSE OLIVEIRA.
Fui alem, em vez de preencher com o objeto eu preenchi direto com o nome do cliente, funciona certinho, acontece que eu preciso do objeto, pois tenho neste todos os dados do cliente
Não sei se fui claro, mas é isto que acontece.

***********************************************************************
Function ObterEntidadesPorChave(cChave)
************************************************************************
private aLista := {}

oCliente := TCliente()    // Instancio o Objeto

cChave := alltrim(cChave)
select CLIE                   // Seleciono a tabela cliente
set order to 2
seek cChave
while(cChave == left(CLIE->CLNOME, len(cChave)) .and. !eof())
   cliente := oCliente:ObterRegistro(.F.) // Aqui eu obtenho o cliente
   MSGINFO('OBJ=' + cliente:clnome) // Para testar mandei exibir o dado do objeto, tudo certo até aqui
   aadd(aLista, cliente)  // Adiciono o objeto na Lista,
   DbSkip(1)
enddo

// introduzido para testar
FOR A = 1 TO LEN(aLista)
   msginfo('Cliente ' + str(A) + ' ' + aLista[A]:clnome) // Quando exibo todos os itens da lista está com o ultimo objeto inserido
next
return(aLista)
Nota de Moderação:
Toledo: Mensagem editada para colocar a tag [ code ]
Veja como utilizar esta tag: Clique aqui
Avatar de usuário

Cavalo Marinho
Usuário Nível 3

Usuário Nível 3
 
Mensagens: 155
Data de registro: 01 Ago 2009 10:01
Cidade/Estado: Aracaju/Se
Curtiu: 3 vezes
Mens.Curtidas: 3 vezes

Montar Array de Objetos no Harbour

Mensagempor JoséQuintas » 19 Jul 2017 10:33

Convém melhorar a parte de variáveis, compilando usando -w3 -es2, já que está elevando o nível dos fontes.

Mas é elementar...
Sua lógica está furada.
Não está garantindo conteúdo único no do while.

E fonte muito feio por sinal.... rs

PRIVATE aLista := {}


Pra que criar como PRIVATE? A compilação -e3 -es2 já reclamaria disto.
Use LOCAL

oCliente := TCliente() 


Acostume com o modo correto: TCliente():New()

dbSkip(1)


É realmente usar isso ao invés de SKIP ? é o dobro de caracteres pra digitar.

return(aLista)


RETURN não é função. É comando !!!
Não é porque aceita errado que deve usar errado
RETURN aLista

Agora vamos ao problema:
Por padrão, array é passado por referência, e seu array é..... PRIVATE, a mesma variável e mesmo array o tempo todo.

E sinceramente, nem entendi seu uso de classe, parece uma classe dentro de outra classe inútil.
Um chute, que deve resolver seu problema, seria este:

FUNCTION ObterEntdadesPorChave( cChave )

   LOCAL aLista := {}

   cChave := Alltrim( cChave )
   SELECT clie
   SET ORDER TO 2
   SEEK cChave
   DO WHILE cChave == Left( CLIE->CLNOME, len( cChave ) ) .AND. ! Eof()
      Aadd( aLista, TCliente():ObterRegistro( .F. ) )
      SKIP
   ENDDO

   Mostra( aLista )
   
   RETURN aLista

STATIC FUNCTION Mostra( aLista )

   LOCAL oElement

   FOR EACH oElement IN aLista
      MsgInfo( oElement:clNome )
   NEXT
   
   RETURN NIL


O que deixa clara a parte esquisita.
Não está criando um array de classes, e sim um array de retornos.
E se só usa o retorno.... pra que classe?
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18116
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1213 vezes

Montar Array de Objetos no Harbour

Mensagempor JoséQuintas » 19 Jul 2017 10:52

Complementando:

Se entendi direito, só está pegando o conteúdo do registro pra usar como classe.
Isso é facilitar erros de fonte.
Seria melhor criar #defines pra estrutura do arquivo e usar array, assim teria controle total no fonte sobre erros.
DESDE QUE COMPILANDO COM -w3 -es2

A mesma coisa, sem classe, e mais seguro: (pelo menos é a impressão que tenho)

#define CLIENTE_NOME       1
#define CLIENTE_ENDERECO 2

FUNCTION Obter( cChave )

   LOCAL aLista := {}
   SEEK cChave
   DO WHILE cChave == clie->clNome  .AND. ! Eof()
      AAdd( aLista, { clie->clNome, clie->clEndereco } )
      SKIP
   ENDDO

   FOR EACH oElement IN aLista
      ? oElement[ CLIENTE_NOME ], oElement[ CLIENTE_ENDERECO ]
   NEXT

   RETURN aLista
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18116
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1213 vezes

Montar Array de Objetos no Harbour

Mensagempor JoséQuintas » 19 Jul 2017 11:02

Se não entendeu porque é mais seguro:
É o simples fato de a compilação já saber se está usando algo que não existe, o compilador poder conferir o seu fonte.

Com Classe, erro somente em run-time:

#include "hbclass.ch"

PROCEDURE Main

   LOCAL oClasse

   oClasse := Classe():New()
   ? oClasse:Minhoca

CREATE CLASS Classe
   VAR Nome
   ENDCLASS


d:\temp>d:\cdrom\fontes\build\build.exe

d:\temp>hbmk2 *.prg *.rc -m -n -w3 -es2 -workdir=c:\temp
hbmk2: Processing environment options: -comp=mingw
hbmk2: Processing configuration: d:\harbour\bin\hbmk.hbc
Harbour 3.4.0dev (f8911388ba) (2017-06-04 18:03)
Copyright (c) 1999-2017, https://github.com/vszakats/harbour-core/
Compiling 'test.prg'...
Lines 725, Functions/Procedures 2
Generating C source output to 'c:\temp\test.c'... Done.
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2017
UPX 3.94w Markus Oberhumer, Laszlo Molnar & John Reiser May 12th 2017

File size Ratio Format Name
-------------------- ------ ----------- -----------
1044992 -> 393728 37.68% win32/pe test.exe

Packed 1 file.

d:\temp>test

Error BASE/1004 Message not found: CLASSE:MINHOCA
Called from __ERRRT_SBASE(0)
Called from CLASSE:ERROR(0)
Called from (b)HBOBJECT(0)
Called from CLASSE:MSGNOTFOUND(0)
Called from CLASSE:MINHOCA(0)
Called from MAIN(8)
d:\temp>


Com #define, erro já na compilação

#define CLIENTE_NOME 1

PROCEDURE Main

   LOCAL oVar := {}

   ? oVar[ CLIENTE_MINHOCA ]


d:\temp>hbmk2 *.prg *.rc -m -n -w3 -es2 -workdir=c:\temp
hbmk2: Processing environment options: -comp=mingw
hbmk2: Processing configuration: d:\harbour\bin\hbmk.hbc
Harbour 3.4.0dev (f8911388ba) (2017-06-04 18:03)
Copyright (c) 1999-2017, https://github.com/vszakats/harbour-core/
Compiling 'test.prg'...

test.prg:7: warning W0001 Ambiguous reference 'CLIENTE_MINHOCA'
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18116
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1213 vezes

Montar Array de Objetos no Harbour

Mensagempor Claudio Soto » 19 Jul 2017 16:15

El problema está en que los objetos son como los array se crean por referencia y por lo tanto cada elemento de la matriz debe contener una instancia diferente del objeto de lo contrario todos los elementos apuntaran a la misma instancia del objeto.

oCliente := TCliente()

Esta sentencia debe ir dentro del while para que a cada registro se cree una nueva instancia del objeto.
Saludos.
Dr. Claudio Soto
(Uruguay)
http://srvet.blogspot.com
Avatar de usuário

Claudio Soto
Colaborador

Colaborador
 
Mensagens: 555
Data de registro: 27 Ago 2012 12:31
Cidade/Estado: Uruguay
Curtiu: 35 vezes
Mens.Curtidas: 166 vezes

Montar Array de Objetos no Harbour

Mensagempor JoséQuintas » 19 Jul 2017 16:29

O fonte confunde.

Não reparou em uma coisa:
O que ele coloca no array não é o objeto, é um retorno.
Acho que nem importa se o objeto está dentro ou fora do do while, nesse caso, mas só dá pra saber olhando o fonte da classe, se existe New() ou Init() fazendo alguma coisa.

cliente := oCliente:ObterRegistro(.F.) 
   aadd(aLista, cliente) 
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18116
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1213 vezes

Montar Array de Objetos no Harbour

Mensagempor Cavalo Marinho » 19 Jul 2017 18:36

ok
Obrigado por responder Jose Quintas
Mas não resolveu o meu caso do jeito que eu pretendo, do jeito que voce comentou em um dos post eu ja tinha feito e é assim que está funcionando no momento
DO WHILE cChave == clie->clNome .AND. ! Eof()
AAdd( aLista, { clie->clNome, clie->clEndereco } )
SKIP
ENDDO
Veja bem, meu código pode até está feio, não ser dos melhores pois não sou tão bom programador como os mestes deste forum, mas eu acho que o array deve ter algum tipo de bug pois se eu faço assim como o codigo acima funciona normal sem problema, mas eu queria ir mais alem, Criei uma classe Pai chamada Entity onde representa uma tabela, já tenho muitos métodos implementados e funcionando, tais como obterRegistro() GravarRegistro, Pesquisar etc, daí quando instancio uma classe que herda desta classe pai já tenho tudo pronto e funcional, somente alguns métodos mais especifico da classe eu implemento na classe filha, acontece que agora eu sentir a necessidade de obter uma lista de um determinada tabela ou seja quero obter uma lista de um determinado objeto que representa uma linha da tabela, e no meu teste funciona ou seja quando eu obtenho o registro eu trago tudo certo o que acontece é que ao inserir na lista o ultimo sempre atualiza todas a linhas já adicionada na lista.
Exemplo:
obtenho o primeiro registro que satisfaça a minha condição:
JOSE DA SILVA, RUA X
adiciono na lista e mostro a lista com o objeto JOSE DA SILVA, RUA X
obtenho o segundo registro
JOSE DOS SANTOS, RUA B
adiciono a lista e mostro os dois itens da lista, os dois já está com JOSE DOS SANTOS, RUA B
obtenho o terceiro registro
JOSE CARLOS OLIVEIRA, RUA TESTE
adiciono a lista e mostro os três itens da lista, os três já está com JOSE CARLOS OLIVEIRA, RUA TESTE
Acredito eu que seja algum bug na implementação do vetor em memória, pois se passo uma matriz como o exemplo acima funciona normal, só não com objetos.
Avatar de usuário

Cavalo Marinho
Usuário Nível 3

Usuário Nível 3
 
Mensagens: 155
Data de registro: 01 Ago 2009 10:01
Cidade/Estado: Aracaju/Se
Curtiu: 3 vezes
Mens.Curtidas: 3 vezes

Montar Array de Objetos no Harbour

Mensagempor JoséQuintas » 19 Jul 2017 19:06

Ninguém sabe tudo, e muito menos eu.
Estou procurando ensinar o que sei.

array é SEMPRE passado por referência, ao passar um array entre funções, está passando a localização dele e não o conteúdo.
Precisa rever o seu uso de arrays, tanto nesse fonte quanto na classe.

Ao fazer assim: a:= { a, b } , está criando o array do ZERO, portanto não é contaminado com conteúdo anterior, por isso funciona.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18116
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1213 vezes

Montar Array de Objetos no Harbour

Mensagempor JoséQuintas » 19 Jul 2017 19:09

Esqueci de mencionar:
A falta de declaração como variável local pode também trazer problemas, por uma rotina interferir em outra.
Pensa que está usando uma variável quando na verdade está usando outra que já existia.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18116
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1213 vezes

Montar Array de Objetos no Harbour

Mensagempor JoséQuintas » 20 Jul 2017 12:36

Veja um teste interessante:

Isto mostra "A"
PROCEDURE Main

   LOCAL teste := {}

   Funcao( teste )

   ? teste[ 1 ]

   RETURN

FUNCTION Funcao( teste )

   Aadd( teste, "A" )

   RETURN NIL


Isto gera erro em run-time.

PROCEDURE Main

   LOCAL teste := {}

   Funcao( teste )

   ? teste[ 1 ]

   RETURN

FUNCTION Funcao( teste )

   teste := { "A" }

   RETURN NIL


Isto mostra "A"

PROCEDURE Main

   LOCAL teste := {}

   Funcao( @teste )

   ? teste[ 1 ]

   RETURN

FUNCTION Funcao( teste )

   teste := { "A" }

   RETURN NIL


Até tem explicação: o CONTEÚDO da variável array é passado por referência por default, mas o conteúdo não a variável.
Ao atribuir o valor novo, está destruindo o vínculo dos valores do array.
Já passando por referência, é a variável por referência e não o conteúdo, então permanece o conteúdo.

Fico na dúvida se isso é bug ou é proposital, mas dá pra encontrar explicação.... rs
Melhor ficar usando por referência sempre, pra não ter dúvida se vai ou não trocar o conteúdo.

Este último detalhe eu descobri agora, não sabia disso.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18116
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1213 vezes




Retornar para Harbour

Quem está online

Usuários vendo este fórum: clodoaldomonteiro, Google [Bot] e 6 visitantes


Ola Amigo, espero que meu site e forum tem lhe beneficiado, com exemplos e dicas de programacao.
Entao divulgue o link da Doacao abaixo para seus amigos e redes sociais ou faça uma doacao para o site forum...
MUITO OBRIGADO PELA SUA DOACAO!
Faça uma doação para o forum
cron
v
Olá visitante, seja bem-vindo ao Fórum Clipper On Line!
Efetue o seu login ou faça o seu Registro