Newsgroup: it.comp.lang.c++
Titolo: struct da validare

struct Struttura {
   int a;
   int b;
   int c;
}
Ora ho una classe che carica i dati presenti nella struttura con un metodo,
chiamiamolo loadStruct
classe.loadStruct( Struttura );
Il problema è che non è detto che io voglia necessariamente settare tutte e
tre le variabili di Struttura, però voglio che il metodo della classe
capisca quale non è stato settato e lo inizializzi a zero.
Es:
Struttura s;
s.a = 10;
classe.loadStruct( s );
se vado a leggere deve essere:
s.a = 10;
s.b = 0;
s.c = 0;
Come si fa???
ciao, t a

La soluzione più ovvia mi sembra quella di utilizzare una classe: ha tutte
le caratteristiche di una struttura ed in più puoi implementarne un
costruttore che inizializzi le variabili membro a zero.
Una cosa del genere:
class Struttura
{
    public:            // Sarebbe meglio private, ma visto che la vuoi
trattare come struct...
        // Le tue variabili:
        int a,b,c;
        // Il costruttore al quale puoi passare tre inizializzatori o non
passarne alcuno,
        // con conseguente azzeramento grazie ai valori di default:
        Struttura(int x=0, int y=0, int z=0) : a(x), b(y), c(z) {}
        /* ... */
};
Saluti,
Sergio
P.S.
Questa è solo un'implementazione: potresti usare delle funzioni "setter" per
settare i valori in un secondo momento, utilizzare un flag per indicare se
le var. sono o no state inizializzate e farlo successivamente, a seconda
dello stato di questo flag, in un'altra funzione come la tua
loadStruct....per fare tutto ciò devi comunque utilizzare le classi,
piuttosto che le strutture.

 costruttore che inizializzi le variabili membro a zero.
Potevi fare la stessa cosa con struct.
La sola differenza e' che membri e metodi sono pubblici a meno che non si
specifichi diversamente.
Maurus


Ciao Maurus.
Oggi ci siamo scambiati diversi post :-)
Quanto dici č giustissimo.
Io mi riferivo semplicemente al concetto, di classe, tipico della OOP,
contrapposto a quello di struttura, tipico della programmazione procedurale.
E ho utilizzato la parola chiave class per convenzione standard (ed anche
perchč sono abituato a fare cosě, piuttosto che usare la parola chiave
struct!).
Saluti,
Sergio

 Saluti,
E' corretto. La scelta di utilizzare class in luogo di struct mi sembra il
giusto modo di affrontare i problemi in OOP way. A volte, il fatto che il
linguaggio C++ sia di fatto un linguaggio ibrido pone dinnanzi alcuni
problemi di valutazione: scegliere di sviluppare software OOP oppure in
maniera procedurale? Voi che ne pensate? E' un bene lo status ibrido tipico
del C++?
Un saluto a tutto il NG.
ma3x


Ciao ma3x.
Personalmente, penso che il carattere ibrido del C++ sia sì un fattore di
maggiore complessità, ma anche e soprattutto un punto di forza.
Vi sono a mio parere classi di problemi in cui l'approccio procedurale e a
basso livello di astrazione è così evidente da far preferire linguaggi
esclusivamente procedurali.
Classi di problemi in cui la OOP è invece la migliore (quasi unica) strada
percorribile.
Tuttavia, vi sono anche delle situazioni in cui all'approccio OOP va
affiancato, per ragioni di efficienza o quant'altro, quello procedurale.
Ed è qui che il linguaggio C++ sfodera tutta la sua potenza (e forse
complessità).
Questo è il mio parere.
Agli altri la parola.
Sergio

 Agli altri la parola.
Si, il discorso non fa una piega.
Nel mio precedente post non ho detto che il fatto che sia ibrido sia
completamente uno svantaggio. Il problema è che ancora certa gente è
ancorata troppo spesso ai vecchi meccanismi procedurali, tralasciando invece
(a mio parere) le vere potenzialità offerte dall'OOP e caratteristiche
tipiche del C++ per cui è stato scritto.
Ovviamente il caro Bjarne ha pensato bene a garantire la retrocompatibilità
con il C. Ciò ha permesso (e qui concordo pienamente con te Sergio) di
sviluppare un linguaggio estremamente potente, flessibile in quanto la
possibilità di scegliere tra diversi paradigmi di programmazione ne consente
la sua adattabilità in contesti disparati.
Secondo me comunque, l'utilizzo delle struct in C++ dovrebbe limitarsi in
situazioni di oggetti medio-piccoli. D'altronde, struct e class con le
opportune modifiche sono del tutto equivalenti (basta dare un'occhiata al
libro di Eckel per avere una conferma). Ma poichè il concetto di classe è
quello che meglio si adatta all'OOP, ritengo che il suo utilizzo sia
doveroso. Una classe secondo me esprime in maniera assolutamente naturale il
concetto stesso di OGGETTO. Cos'è una classe se non l'insieme di oggetti che
vengono accumunati da caratteristiche, proprietà (attributi) e behaviours
(metodi) analoghi?

 costruttore che inizializzi le variabili membro a zero.
e se ho un array nella classe/struttura e lo inizializzo con il costruttore
poi è probabile che voglia cambiarne le dimensioni. C'è un modo semplice per
fare questo (senza utilizzare vector)?
ciao, t

 (metodi) analoghi?
A questo punto pero' dovresti definire il concetto di oggetto,
altrimenti il tuo discorso non e' che un serpente che si morde la
coda...
Ciao,
Nicola

 Ciao,
Saluti

 Ehm, scusa...ma cos'è...? Interrogazione scolastica??
No, e' una cortese segnalazione del fatto che l'affermazione: 
"Ma poichè il concetto di classe è quello che meglio si adatta
all'OOP, ritengo che il suo utilizzo sia doveroso. Una classe secondo
me esprime in maniera assolutamente naturale il concetto stesso di
OGGETTO. Cos'è una classe se non l'insieme di oggetti che vengono
accumunati da caratteristiche, proprietà (attributi) e behaviours
(metodi) analoghi?"
e' priva di senso compiuto. 
Ciao,
Nicola

 e' priva di senso compiuto.
E' priva di senso compiuto??? A questo punto vengono i dubbi a me riguardo
la tua presunta affermazione denigratoria...

...

Spiego. 
- Il concetto di classe *e'* un elemento fondamentale della
  programmazione ad oggetti; cosa significa dire che vi
  "si adatta"?
- Il fatto di far parte del paradigma OOP rende l'uso di un
  costrutto doveroso? Anche indipendentemente dal contesto al
  quale deve essere applicato?
- "classe" e "oggetto" sono due concetti distinti, per quanto
  strettamente collegati, come correttamente spieghi di seguito:
  cosa significa allora "Una classe esprime il concetto di oggetto"?
Sono convinto che tu sappia cosa intendevi dire, meno del fatto che tu
sia riuscito ad esprimerlo. E considerare doveroso l'utilizzo di un
costrutto solo perche' appartiene ad un particolare paradigma mi pare
molto, ma molto opinabile.
Ciao,
Nicola

  "si adatta"?
Qui non condivido affatto. E' possibile lavorare a oggetti
senza dover necessariamente tirare in ballo le classi.
La classe e' un elemento fondamentale della programmazione
ad oggetti *per come viene vista dal C++*. Questa non e'
pero' l'unica possibilita'.
Andrea

...

Resto del mio punto di vista. Se ragioniamo in termini di
Programmazione Orientata agli Oggetti, astraendo da specifici
linguaggi di programmazione, il concetto di "classe" e' uno dei
cardini del paradigma.
Dopodiche' e' certamente possibile implementare il concetto di classe
in modi diversi in linguaggi diversi, anche senza ricorrere
necessariamente ad eventuali costrutti che per caso si chiamano
"classe".
D'altra parte c'e' chi fa OOP mandando messaggi e chi la fa chiamando
funzioni; in entrambe i casi e' sempre programmazione orientata agli
oggetti (ma questo su comp.lang.smalltalk non lo scrivo :-)
Ciao,
Nicola

"classe".
Credo che, nello specifico, Andrea si riferisse alla possibilita`, in
alcuni linguaggi, di definire oggetti a prescindere dall'esistenza di
una classe.  Nel vecchio TP, per esempio, c'era la keyword "object"
con la quale si potevano definire direttamente le istanze.

 "classe".
concordo con Nicola: la programmazione ad oggetti si basa sul concetto di 
Classe (uso la maiuscola per distinguere) inteso come "insieme di 
oggetti con determinate proprieta`"; spesso e volentieri i linguaggi di 
programmazione implementano le Classi usando "classi", ovvero 
particolari costrutti del linguaggio.
Del resto anche in C++ e` possibile implementare delle Classi senza usare 
le "classi": basta usare una struct, ad esempio: e` pur vero che struct 
e class sono semanticamente *molto* simili, ma si tratta pur sempre di 
due costrutti diversi.
Un altro esempio mi viene dal python:
foo = type('foo', (), {})
e` una classe del tutto equivalente (a dire il vero c'e` una differenza 
fondamentale, ma non e` importante ai fini del nostro discorso) a
class foo:
    pass
anche se nel primo caso abbiamo creato una Classe senza utilizzare alcuna 
classe (se stessi scrivendo in inglese il gioco di parole sarebbe 
senz'altro piu` bello ;-)
In conclusione riscriverei il messaggio di Nicola cosi`:
"""
Il concetto di Classe *e'* un elemento fondamentale della
programmazione ad oggetti
""" [notare la maisucola]
Giustamente Andrea dice anche che:
"""
E' possibile lavorare a oggetti
senza dover necessariamente tirare in ballo le classi.
""" [notare la minuscola]
ciao Anto
-- 
"Computer science is not about computers any more than astronomy
is about telescopes." -- EW Dijkstra

cardini del paradigma.
Ovviamente non c'e' modo di contestare una definizione...
per me puoi chiamare programmazione ad oggetti quello che
ti pare. Ci sono comunque in uso altre versioni della
definizione di programmazione ad oggetti che non richiedono
affatto l'esistenza di un concetto di classe.
In C++ un oggetto puo' esistere solo come istanza di una
classe... e le classi non sono oggetti; esiste un dualismo
fra classi e istanze simile a quello fra record e schema
di un DB relazionale (i DB che conosco usano sempre delle
tabelle per rappresentare uno schema... ma l'analogia fra
record e' tabelle e' solo parziale; le operazioni consentite
sullo schema sono diverse da quelle consentite sulle altre
tabelle). Ci sono nel C++ delle "sporcature", come gli
attributi statici (che appartengono a qualcosa che e' una
specie di oggetto e di cui esiste una e una sola specie
di istanza), ma la distinzione fra cosa e' un oggetto e
cosa e' una classe e' netta.
Esistono pero' altre possibilita'. Un linguaggio in cui
il dualismo classe/oggetto non esiste e dove cioe' esistono
solo gli oggetti e' Self. In Coplien ("Advanced C++ Programming
Styles and Idioms") ho visto definire questi linguaggi
come basati su exemplars. Io conosco Self solo superficialmente
da un articolo letto molti anni fa in cui quello che era
descritto era un'idea di processore progettato per facilitare
l'esecuzione di programmi di quel tipo...
Non conosco nulla della sintassi di Self, ma ne conosco alcune
delle idee di base che ho usato in passato programmando in C.
Per spiegare come funzionano ti parlero' di uno dei tanti
linguaggi di script che ho implementato che usa un approccio
abbastanza simile a Self.
Esistono alcuni tipi base:
  - nessun valore
  - interi
  - double
  - stringhe
  - array
  - oggetti
  - metodi
Il linguaggio e' typeless (o per meglio dire "dynamically typed")
e ogni variabile puo' cambiare "tipo" durante l'esecuzione.
A parte gli altri tipi base che credo siano abbastanza ovvi
ci sono gli oggetti e i metodi.
Un oggetto e' una collezione di valori indicizzati per nome,
e l'operatore di accesso ad un campo e' il ".".
Diversamente dal C++ quali siano gli attributi di un oggetto
e' qualcosa che puo' cambiare dinamicamente durante l'esecuzione.
Il linguaggio e' "ortogonale", nel senso ogni volta che si parla
di un valore questo puo' avere uno qualunque dei tipi citati.
Quando si mette un attributo in un oggetto questo puo' essere
dichiarato come semplice campo, oppure come parent.
Questi attributi "parent" sono l'aggancio che viene usato per
fornire il meccanismo di ereditarieta'.
Se in MySelf scrivo
   a = b.x;
e b e' di tipo oggetto quello che ottengo e' che il campo 'x'
viene ricercato nell'oggetto b. Se la ricerca ha successo
allora quello e' il valore restituito... se invece la ricerca
non ha successo e l'oggetto b ha dei campi dichiarati "parent"
che sono di tipo oggetto la ricerca prosegue (ricorsivamente)
in questi parent.
Quando scrivo invece
   b.x = a;
quello che ottengo e' che il campo x da modificare viene
cercato in b, e se non e' presente viene aggiunto a b senza
effettuare la ricerca ricorsiva fatta in caso di lettura.
I valori di tipo method sono sostanzialmente delle funzioni
che vengono definite con la sintassi
  method(...parametri...){ ... codice ... }
la sintassi
  a.foo(...)
effettua la chiamata del metodo contenuto nel campo foo per
l'oggetto a (nel caso che ovviamente questo contenuto sia
di tipo "metodo").
Diversamente dal C++ quali sono i campi di un oggetto e'
qualcosa che puo' variare a runtime, come anche quali sono
gli oggetti "parent" di un oggetto, come anche quali sono
i metodi definiti per un oggetto.
Sostanzialemente quello che e' il concetto di "classe" e'
totalmente assente... una determinata istanza puo' avere
un determinato metodo oppure no, ma e' una relazione fra
istanze (che peraltro puo' cambiare a runtime).
L'ereditarieta' funziona in modo abbastanza semplice: se
scrivo...
  def make_window()
  {
    return object(
      x0=0, y0=0, x1=100, y1=100
      draw=method(dest)
      {
        ....
      }
      ok_to_close=method() { return 1; }
    );
  }
  def make_custom_window()
  {
    return object(
      window := make_window()  // Notare: ":="
      draw = method(dest)
      {
        .window.draw(); // Chiama la versione base
        ... codice di draw aggiunto ...
      }
      ...
    );
  }
Il carattere ":=" indica l'aggiunta definizione di un
attributo di tipo "parent".
Ci sono ovviamente *moltissimi* dettagli che sarebbe troppo
lungo descrivere qui... comunque quello che segue e' un
piccolo esempio di codice
def make_drawing()
{
  return object(
    observers = make_list()
    entities = make_list()
    ... cut ...
    notify_observers=method()
    {
      if (!.locked)
        .observers.foreach(object(f=method(x){
          x.notify();
        }));
    }
    add_observer=method(o)
    {
      .observers.add(o);
    }
    remove_observer=method(o)
    {
      .observers.remove(o);
    }
  );
}
La funzione make_drawing crea un oggetto drawing che
contiene delle entita' e una lista di "osservatori".
Questi osservatori possono "registrarsi" presso l'oggetto
drawing per essere informati di quando cambia qualcosa.
Non esiste nessuna dichiarazione su tipo di questi
osservatori... l'unica cosa che accade e' che il
metodo "notify" verra' chiamato per ogni osservatore.
Ovviamente a livello di descrizione la classe e' un
concetto presente (parlo di "drawing", e viene naturale
pensare al denominatore comune di tutte le istanze
restituite da make_drawing) ma questo e' totalmente
assente a livello di programmazione e si tratta comunque
di una classe astratta molto diversa dal concetto di
classe che ha il C++.
Ci sono solo istanze, metodi, ereditarieta' (multipla)
ottenuta con il meccanismo della delega e il tutto dinamico.
Non esiste nessun ".h" ... gli oggetti sono creati da
funzioni oppure da metodi di altri oggetti. Da nessuna
parte definisco cosa e' un "drawing" come concetto logico...
ci sono oggetti che posso passare al metodo "add_observer"
di un oggetto ottenuto da make_drawing, e altri che non
posso passare. Ma se posso passare un oggeto o meno e'
qualcosa che dipende anche dal momento (il metodo "notify"
puo' essere aggiunto o tolto). Chi viene passato a
"add_observer" non appartiene a nessuna "classe".
In particolare non ha senso domandarsi di che "tipo"
e' una determinata istanza creata con object().
Ci sono ovviamente molte semplificazioni sintattiche
che ho aggiunto per comodita'... ad esempio e' possibile
aggiungere una serie di attributi ad un oggetto al
momento della creazione (vedi sopra) come e' anche
possibile usare la sintassi
  return object(
     f(x,y) { .... }
  );
invece della piu' prolissa
  return object(
    f = method(x,y) { ... }
  );
come anche e' possibile fare l'overload degli operatori
per le classi con sintassi del tipo
  return object(
    "this[x]"(x) { ... definisce a[x] (lettura)... }
    "this[x]=y"(x,y) { ... definisce a[x]=y (scrittura) ... }
  );
Andrea
PS:
  Il C++ fra l'altro permette di implementare anche
  questo tipo di approccio in modo abbastanza
  soddisfacente a parte l'impedimento di sintassi
  come a.x o .x che obbliga a ripiegare su cose molto meno
  efficaci come a["x"] e alla fastidiosa impossibilita'
  di avere la conversione dei nomi di campo in costanti
  numeriche univoche a compile time che comporta
  ovviamente prestazioni scandalose (a volte la rozzezza
  dei template e' veramente fastidiosa).

 e' una determinata istanza creata con object().
e` di tipo object, no?
ciao Anto
PS: per chi conosce il python: e` vero, ho mentito: quello che ho scritto 
e` vero solo se e` presente un attributo globale __metaclass__ che ha 
valore 'type'. Pero` questo non muta il senso del discorso, anche 
perche` in una delle prossime release di python 'type' dovrebbe essere 
proprio la metaclasse di default.


proprio la metaclasse di default.
Questo problema delle "metaclassi" di cui si parla
spesso e' proprio dovuto al rendersi conto che
anche una classe in fondo e' una istanza di qualcosa,
e questa nostra perversione mentale del dover
necessariamente incasellare ci fa impazzire dal
desiderio di sapere "si... ma istanza di cosa ???".
A mio parere comunque tirare in ballo le metaclassi
non risolve il conflitto filosofico di fondo... non
fa che aggiungere solo un altro livello.
In un linguaggio come MySelf si scrive semplicemente
   object( x=100, y=200 )
Il voler a tutti i costi incasellare questo elemento
(oltre alla sua naturale casella di "object") e'
qualcosa che il linguaggio lascia ai filosofi.
Andrea

 desiderio di sapere "si... ma istanza di cosa ???".
hai ragione. In Python tutto, compreso 'type', e` una istanza di 'type. 
Pero` le metaclassi hanno senso e, anzi, sono molto utili.
ciao Anto
PS: domani parto e vado tre giorni a sciare, per cui non potro` 
rispondere subito
