Montar Array de Objetos no Harbour

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

Moderador: Moderadores

Avatar do usuário
Cavalo Marinho
Usuário Nível 3
Usuário Nível 3
Mensagens: 156
Registrado em: 01 Ago 2009 10:01
Localização: Aracaju/Se

Montar Array de Objetos no Harbour

Mensagem por Cavalo Marinho »

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.

Código: Selecionar todos

***********************************************************************
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)
Editado pela última vez por Toledo em 19 Jul 2017 12:14, em um total de 1 vez.
Razão: Mensagem editada para colocar a tag [ code ]<br>Veja como utilizar esta tag: http://www.pctoledo.com.br/forum/faq.php?mode=bbcode#f2r1
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Montar Array de Objetos no Harbour

Mensagem por JoséQuintas »

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

Código: Selecionar todos

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

Código: Selecionar todos

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

Código: Selecionar todos

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

Código: Selecionar todos

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:

Código: Selecionar todos

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 mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"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 do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Montar Array de Objetos no Harbour

Mensagem por JoséQuintas »

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)

Código: Selecionar todos

#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 mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"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 do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Montar Array de Objetos no Harbour

Mensagem por JoséQuintas »

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:

Código: Selecionar todos

#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

Código: Selecionar todos

#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 mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Claudio Soto
Colaborador
Colaborador
Mensagens: 566
Registrado em: 27 Ago 2012 12:31
Localização: Uruguay
Contato:

Montar Array de Objetos no Harbour

Mensagem por Claudio Soto »

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 do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Montar Array de Objetos no Harbour

Mensagem por JoséQuintas »

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.

Código: Selecionar todos

cliente := oCliente:ObterRegistro(.F.) 
   aadd(aLista, cliente) 
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"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 do usuário
Cavalo Marinho
Usuário Nível 3
Usuário Nível 3
Mensagens: 156
Registrado em: 01 Ago 2009 10:01
Localização: Aracaju/Se

Montar Array de Objetos no Harbour

Mensagem por Cavalo Marinho »

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 do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Montar Array de Objetos no Harbour

Mensagem por JoséQuintas »

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 mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"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 do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Montar Array de Objetos no Harbour

Mensagem por JoséQuintas »

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 mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"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 do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Montar Array de Objetos no Harbour

Mensagem por JoséQuintas »

Veja um teste interessante:

Isto mostra "A"

Código: Selecionar todos

PROCEDURE Main

   LOCAL teste := {}

   Funcao( teste )

   ? teste[ 1 ]

   RETURN

FUNCTION Funcao( teste )

   Aadd( teste, "A" )

   RETURN NIL

Isto gera erro em run-time.

Código: Selecionar todos

PROCEDURE Main

   LOCAL teste := {}

   Funcao( teste )

   ? teste[ 1 ]

   RETURN

FUNCTION Funcao( teste )

   teste := { "A" }

   RETURN NIL

Isto mostra "A"

Código: Selecionar todos

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 mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"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 do usuário
deividdjs
Usuário Nível 3
Usuário Nível 3
Mensagens: 377
Registrado em: 19 Set 2006 09:39
Localização: Foz do Iguaçu / Pr

Montar Array de Objetos no Harbour

Mensagem por deividdjs »

tarde amigos !!

Código: Selecionar todos

FUNCTION CarregarContas()
   
   LOCAL aContas, dHoje, cliant 
    aContas := {}
    dHoje := DATE()

	 RECEBER->(ORDSETFOCUS("RECCX_18"))
	 RECEBER->(DBGOTOP())
	 do while RECEBER->cd_dtvenc < date() .and. RECEBER->cc_receb == ' ' .and. RECEBER->(!EOF())
		
	  	 if RECEBER->cc_codcli <> cliant 
          AADD(aContas, { receber->cc_codcli, receber->cd_dtvenc })
		 endif   
 		 cliant := RECEBER->cc_codcli 
		 RECEBER->(DBSKIP())
		
	 enddo

    Mostra_array(aContas)

    RETURN aContas
 
 //------------------------------------------------------------------------------------------------------------------

static FUNCTION Mostra_array( aContas )
   
	LOCAL oElement

   
   FOR EACH oElement IN aContas
	      alert( oElement:CC_CODCLI, oElement:CD_DTVENC )
   NEXT
   
   
   RETURN NIL
não consigo mostrar no alert o conteudo de aContas ... dá erro .. alguem sabe por qual motivo ??

Saludos,
Anexos
array.png
Windows 11 + Harbour 3.2 + MINGW64 gcc 14.1.0 + Visual Lib + GTWVG + LETODBF WINDOWNS/LINUX
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Montar Array de Objetos no Harbour

Mensagem por JoséQuintas »

Confundiu array com classe.
Adicionou dois elementos no array: oElement[1] e oElement[2]

Também pode usar hb_ValToExp( aContas ) ou hb_ValToExp( oElement )
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"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 do usuário
deividdjs
Usuário Nível 3
Usuário Nível 3
Mensagens: 377
Registrado em: 19 Set 2006 09:39
Localização: Foz do Iguaçu / Pr

Montar Array de Objetos no Harbour

Mensagem por deividdjs »

show .. funcionou ! obrigado

Saludos,
Windows 11 + Harbour 3.2 + MINGW64 gcc 14.1.0 + Visual Lib + GTWVG + LETODBF WINDOWNS/LINUX
Responder