[Chiuso] Classi: costruttore di copia, overload operatori e passare parametri tramite costruttore

Stato
Chiusa ad ulteriori risposte.

ing82

Utente junior
Original poster
20 Maggio 2022
26
1
3
excel 2019
Aggiungo qualche riga di codice alla classe Point che sto implementando per studiare/capire le classi del VBA in merito a costruttore di copia, overload operatori e passare parametri tramite costruttore.
Sono tutte funzionalità che se non ho sbagliato a capire, sono assenti nel VBA, e al massimo ci si può inventare qualcosa per aggirare queste carenze.

In particolare, nel codice seguente:

clone() serve a creare un nuovo punto come copia dell'originale (bypassa costruttore di copia)

assign(ByVal P As Point) copia un punto in un altro (bypassa l'overload dell'operatore di assegnamento)

make(ByVal x As Double, ByVal y As Double, ByVal z As Double) As Point crea un nuovo punto assegnandogli le coordinate passate come parametri (bypassa l'impossibilità di passare parametri tramite il costruttore)

Modulo di classe:
Public mX As Double 'variabile membro per la coordinata x
Public mY As Double 'variabile membro per la coordinata y
Public mZ As Double 'variabile membro pe la coordinata z

Private Sub Class_Initialize()
    mX = 0#
    mY = 0#
    mZ = 0#
End Sub

Private Sub Class_Terminate()
    'per ora nessuna operazione
End Sub

Public Property Get x() As Double
    x = mX
End Property

Public Property Get y() As Double
    y = mY
End Property

Public Property Get z() As Double
    z = mZ
End Property

Public Property Let x(ByVal x As Double)
    mX = x
End Property

Public Property Let y(ByVal y As Double)
    mY = y
End Property

Public Property Let z(ByVal z As Double)
    mZ = z
End Property

Public Sub setCoordinates(ByVal x As Double, ByVal y As Double, ByVal z As Double)
    mX = x
    mY = y
    mZ = z
End Sub

Public Function clone() As Point
    Dim P As Point
    Set P = New Point
    Call P.setCoordinates(mX, mY, mZ)
    Set clone = P
End Function

Public Sub assign(ByVal P As Point)
    mX = P.x()
    mY = P.y()
    mZ = P.z()
End Sub

Public Function make(ByVal x As Double, ByVal y As Double, ByVal z As Double) As Point
    Dim P As Point
    Set P = New Point
    Call P.setCoordinates(x, y, z)
    Set make = P
End Function

per far funzionare make in questo modo

Visual Basic:
Dim P As Point
Set P = Point.make(-53.2, -45.6, 3.14)
è necessario impostare Attribute VB_PredeclaredId = True (v. questo esempio).
A questo link però, dopo aver descritto questa soluzione, trovo le seguenti affermazioni:

The attribute is VB_PredeclaredId, which is False by default. At a low level, each object instance has an ID; by toggling this attribute value, you tell VBA to pre-declare that ID… and that’s how you get what’s essentially a global-scope free-for-all instance of your object.
That can be a good thing… but as is often the case with forms (which also have a predeclared ID), storing state in that instance leads to needless bugs and complications.
Qualcuno sa spiegarmi terra-terra che genere di problemi possono nascere?
Qualche commento/miglioria alle altre due funzioni, assign e clone?
 

muni

VBA Expert
Expert
25 Novembre 2018
1.181
227
65
Roma
2019
VBA non è un linguaggio OO. Come non lo era VB4, 5, 6 ... Perché cerchi in VBA qualcosa che non esiste e non è mai stato implementato?

Le classi e gli oggetti di VBA sono primordiali, non ha senso cercare di farci cose come se fosse Java o C++.


Comunque, perché dichiari come Public le variabili membro? C'è un motivo particolare?
 

ing82

Utente junior
Original poster
20 Maggio 2022
26
1
3
excel 2019
Perché cerchi in VBA qualcosa che non esiste e non è mai stato implementato?
Perchè ho scoperto dell'esistenza delle classi in VBA, e sto cercando di capire fin dove possono arrivare, tutto qui: mi sono dato qualche giorno di tempo per studiarmele a grandi linee e poi trarre le mi conclusioni.

perché dichiari come Public le variabili membro? C'è un motivo particolare?
ovviamente devono essere Private, ma nell'esempio che si può trovare al link che ho postato, c'è l'istruzione With...end with, con la quale assegna i valori dei parametri ai dati membro della classe, ma a me non funziona, quindi ho provato a modificare in public per capire se potesse essere quello il problema, ma neppure quello, quindi ho lasciato perdere il with...end with e ho fatto a modo mio, come riportato sopra.
 

muni

VBA Expert
Expert
25 Novembre 2018
1.181
227
65
Roma
2019
Perchè ho scoperto dell'esistenza delle classi in VBA, e sto cercando di capire fin dove possono arrivare, tutto qui: mi sono dato qualche giorno di tempo per studiarmele a grandi linee e poi trarre le mi conclusioni.

VBA è nato decenni fa. Le classi erano uno "zucchero sintattico", non era programmazione Object Oriented. Non è stato implementato praticamente nulla della OOP e quello che c'è, molte volte, non rispetta lo standard. E' una programmazione "Event Driven". Le classi in VB(A/6) servono poche volte e comunque non rendono OO un codice.

Non ha molto senso perderci molto tempo dietro. Meglio studiare a fondo C# e Java. Il C++ è un pelino più complesso ma è destinato ad applicazioni specifiche.

ovviamente devono essere Private,

Ecco

ho fatto a modo mio

Resta il fatto che i membri devono essere privati, è la base della OOP.
 

ing82

Utente junior
Original poster
20 Maggio 2022
26
1
3
excel 2019
...

Ho fatto a modo mio nel senso che non funzionando la porzione with...end with, ho aggirato il problema, i dati membro sono rimasti public ma avrebbero dovuto essere rimessi private, ma ora poco importa, direi che ho capito che le classi del VBA, se possono tornare utili e per quello che potrebbero servire a me è invece di scrivere una funzione che prende in input il punto da traslare passato byref e le componenti della traslazione, richiamo addirittura P.translate, ma direi niente di più.
Grazie a tutti
 

Sgrubak

Excel/VBA Expert
Expert
10 Marzo 2022
770
164
45
Office 365 Beta
In particolare, nel codice seguente:
Secondo me ti complichi la vita inutilmente. Bastano due funzioni e fai tutte e quattro le cose:
- su setCoordinates() mi trovi d'accordo;
- clone() forse ha senso ma è prolissa
Visual Basic:
Public Function clone() As Point
    Set clone = New Point
    Call clone.setCoordinates(mX, mY, mZ)
End Function
- assign() è un doppione di clone() che per di più ti costringe a creare preventivamente un nuovo punto, quando clone lo fa già da sola; NOTA: Questo discorso vale solo e soltanto perché un punto è definito solamente dalle sue coordinate, pertanto copiarlo equivale ad assegnare le stesse identiche coordinate e comunque non ne vedo il senso geometrico: il punto è univoco nello spazio quindi se lo hai già definito, a cosa ti serve clonarlo?
- make() non esistendo (a differenza del VB.NET) la keyword Shared ti costringe a creare un'istanza di un punto ed usare quella per crearne un altro... Se ne hai già uno a disposizione potrebbe essere comodo, ma se non ce l'hai qual è la differenza tra crearlo e chiamare setCoordinates() invece che crearlo ed usarlo per crearne un altro passando gli stessi argomenti alla make()? Crea la Factory (come suggerisce il link che hai trovato) che espone il metodo NewPoint(x, y, z) e allora mi trovi d'accordo. Istanzi una nuova Factory a livello di modulo e quando ti serve un punto usi sempre la stessa Factory, così riduci il codice da scrivere in maniera drastica.

Ridurrei quindi alle sole setCoordinates() e alla NewPoint() della factory.

E comunque un informatico direbbe che stai "reinventado la ruota". 😁 Qui qualcuno ha già fatto tutto il lavoro per te: GeometRi per C# e geometry per C++.
 

ing82

Utente junior
Original poster
20 Maggio 2022
26
1
3
excel 2019
alla classe Point che sto implementando per studiare/capire
alla fine per intendersi qualche riga di codice bisogna pur mostrarla: la classe point è quella più basilare che poteva servire a questo scopo, avrei potuto prendere la classe persona riportata da altri esempi, ma scrivere per scrivere...

assign e clone fanno cose simili ma non uguali: clone crea una copia del punto esistente, quindi crea un punto nuovo, assign lavora su due punti già esistenti, e ne rende uguali le coordinate.
Lo scopo è puramente didattico, se ha senso fisico o meno, in questo momento non importa.

make, se si modifica VB_PredeclaredId da False a True, permette di non dover usare un altro punto per sfruttarla, ma cambiare da false a true sembra che comporti qualche possibile problemino in più, ma chi ha scritto questa affermazione, sempre qui, non ha dettagliato a cosa si può andare incontro, e infatti chiedevo lumi a riguardo (v. sotto)
è necessario impostare Attribute VB_PredeclaredId = True (v. questo esempio).
A questo link però, dopo aver descritto questa soluzione, trovo le seguenti affermazioni:

The attribute is VB_PredeclaredId, which is False by default. At a low level, each object instance has an ID; by toggling this attribute value, you tell VBA to pre-declare that ID… and that’s how you get what’s essentially a global-scope free-for-all instance of your object.
That can be a good thing… but as is often the case with forms (which also have a predeclared ID), storing state in that instance leads to needless bugs and complications.
Qualcuno sa spiegarmi terra-terra che genere di problemi possono nascere?


Grazie
 

Sgrubak

Excel/VBA Expert
Expert
10 Marzo 2022
770
164
45
Office 365 Beta
alla fine per intendersi qualche riga di codice bisogna pur mostrarla: la classe point è quella più basilare che poteva servire a questo scopo, avrei potuto prendere la classe persona riportata da altri esempi, ma scrivere per scrivere...
Ci sta. Avevo inteso che la classe dei punti fosse quella necessaria al tuo lavoro e quindi cercavo di ragionare in quell'ottica. Alle volte si cercano soluzioni generali che son complesse, quando limitandosi al contesto specifico si riescono a trovare soluzioni meno flessibili ma più "semplici".

permette di non dover usare un altro punto per sfruttarla
Non esattamente. Settare VB_PredeclaredId = True impone al compilatore di creare un'istanza globale dell'oggetto. Quindi un'istanza comunque ce l'hai e per di più è globale, e il pericolo sta tutto li.
chi ha scritto questa affermazione, sempre qui, non ha dettagliato a cosa si può andare incontro, e infatti chiedevo lumi a riguardo
Le variabili globali sono la maniera più veloce per propagare malfunzionamenti nel codice: se il metodo make() risulta dipendere dallo stato interno dell'oggetto (per un motivo qualsiasi), e questo stato viene modificato, fatichi a trovare chi te lo modifica. Magari hai 10 routine che lavorano sull'istanza globale e debuggare quale crea rogne è un inferno...

In pratica scrivi la classe, esporti il sorgente in un editor esterno per poter modificare l'attributo, lo reimporti e ti esponi a possibili bug quando in un modulo generico ti basta una funzione pubblica che ti mette al riparo da parecchie rogne (a meno di non far dipendere questa funzione da variabili locali al modulo, ma li è darsi la zappa sui piedi)
 

6DiegoDiego9

Utente abituale
6 Aprile 2022
127
10
18
Milano nord
2018
Le variabili globali sono la maniera più veloce per propagare malfunzionamenti nel codice: se il metodo make() risulta dipendere dallo stato interno dell'oggetto (per un motivo qualsiasi), e questo stato viene modificato, fatichi a trovare chi te lo modifica. Magari hai 10 routine che lavorano sull'istanza globale e debuggare quale crea rogne è un inferno...

Per capire al volo "chi" modifica una variabile, anche dentro una classe predeclared, metti un Break When Value Changes nella Watch Window e poi guarda il Call Stack della Locals Window.
 

alfrimpa

VBA Expert
Supermoderatore
18 Dicembre 2015
49.133
4.192
2.445
69
Napoli
Office 365
Siamo nella sezione “Excel VBA e macro”

In questa discussione da cosa si evince che si sta parlando di VBA?

Sposto la discussione nella sezione Visual Basic che mi sembra più consona.
 
Ultima modifica:

6DiegoDiego9

Utente abituale
6 Aprile 2022
127
10
18
Milano nord
2018
Aggiungo qualche riga di codice alla classe Point che sto implementando per studiare/capire le classi del VBA in merito a costruttore di copia, overload operatori e passare parametri

Visual Basic:
Dim P As Point
Set P = Point.make(-53.2, -45.6, 3.14)
è necessario impostare Attribute VB_PredeclaredId = True (v. questo esempio).
Se predeclari Point, non puoi usare quel codice.

Puoi usare:
Visual Basic:
Dim P As New Point
Set P = Point.make(-53.2, -45.6, 3.14)

oppure meglio direttamente:
Visual Basic:
Point.make(-53.2, -45.6, 3.14)

Comunque non vedo il senso del predeclare a questo fine.
Per costruire con parametri, non essendo possibile in singola istruzione in VBA, il metodo semplice che uso è aggiungere una sub "Init" o "Inizializza" o alla classe, richiamando sempre la sub con una riga in più dopo la riga di costruzione. Come nel primo esempio qui sopra ma invece di "make" preferisco chiamarla "Init" per evitare fraintendimenti.
 

alfrimpa

VBA Expert
Supermoderatore
18 Dicembre 2015
49.133
4.192
2.445
69
Napoli
Office 365
E allora ti chiedo in questa discussione da cosa si evince che si sta parlando di VBA?

Se me lo dici non ho nessun problema a spostare nuovamente la discussione.
 

6DiegoDiego9

Utente abituale
6 Aprile 2022
127
10
18
Milano nord
2018
Humm, ing82 chiede soluzioni VBA ed io gli sto rispondendo solo su VBA. Di istruzioni non-VBA comunque non vedo nulla neanche da parte altrui. Boh, da cosa si evince che qualcuno tratti di non-VBA? SmileFace
 
Stato
Chiusa ad ulteriori risposte.