Newsgroup: it.comp.lang.c++
Titolo: xchè i metodi static non possono essere const?

Ciao a tutti,
mi sapete dare una buona ragione perchè un metodo static non può essere
dichiarato const?!
GRAZIE
Daniele.

dichiarato const?!
A me la cosa sembra sensata: se un metodo e' dichiarato
"const" significa che non modifica l'istanza puntata da
"this" (o per meglio dire significa che e' usabile quando
l'istanza puntata da "this" e' un oggetto "const")...
i metodi statici non hanno nessun "this" e quindi che
senso avrebbe la distinzione fra "const" e "non-const" ?
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

 senso avrebbe la distinzione fra "const" e "non-const" ?
Diciamo che un metodo static può operare solo su membri *statici* della
classe.
Un metodo static const significa che non modifica i membri statici di
quella classe!
Daniele.

dichiarato const?!
Si tratta più che altro di un'operazione che non ha significato(alle
funzioni membro static infatti non viene passato il puntatore this che
nelle funzioni membro const invece non può essere modificato), ma il
c++ decide comunque di segnalare un errore,e ti assicuro che questo é
un bene perché evita inutili confusioni da parte del programmatore
facendogli capire che la sua operazione é errata.
Il Ghenio
WINWORD.EXE - ERRORE DI APPLICAZIONE
l'istruzione a "0x3017ff27"ha fatto riferimento alla
memoria a "0x02a3143c".La memoria non poteva essere 'read'.


Il fatto che il membro sia o meno const non serve per sapere a livello
astratto
che non modifica i membri della classe. Serve per sapere che, siccome
non li modifica,
puo' essere chiamato anche se l'oggetto in questione e' costante.
L'informazione vera non e' nella presenza di const ma nella sua
assenza. Ovvero se un
membro non e' const allora non puo' sempre essere chiamato.
Il compilatore ragiona al contrario: un membro non statico di una
classe per lui e' const. A meno che non ometti di dichiararlo tale. I
membri che tu hai omesso di dichiarare const sono speciali e in
particolare non possono essere sempre chiamati.
Per i membri static questo non vale: possono sempre essere chiamati.
Cosa poi modifichino o meno al compilatore frega poco.
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556

 statici di quella classe!
Idea interessante. Personalmente non riesco a pensare ad
un caso pratico in cui possa tornare utile; pero' potrebbe
avere qualche senso.
Personalmente sono convinto che l'uso di data member static
del C++ sia un po' limitante... le classi possono essere
utilizzate un po' come delle istanze di cui esiste un solo
esemplare ma non credo che sia una soluzione corretta.
Pur avendo usato la cosa per pigrizia in qualche occasione
trovo che la presenza di data member statici sia una
stortura (probabilmente la soluzione giusta da un punto di
vista filosofico sarebbe un singleton).
Andrea
--
----------------------------------------------------------------
 <\___/>  Andrea        email: agriff at tin dot it
 / . . \  "6502"          irc: _6502_@EFNET#italia
(  (")  ) Griffini   homepage: 
http://www.netservers.com/~agriff
Sent via Deja.com
http://www.deja.com/

 vista filosofico sarebbe un singleton).
Ci sei!
A livello filosofico, ad ogni "tipo" (nel senso del C++) corrispondono
non una ma due classi. Una e' la classe che rappresenta il tipo stesso
(la class del C++). L'altra e' una metaclasse. Ovvero la classe della
classe. Per spiegarlo dobbiamo "uscire" dal mondo C++, nel quale la
closure riflessiva dei tipi non e' totalmente implementata.
Non voglio fare riferimento ad un linguaggio specifico (per questi
ragionamenti si usa in generale lo Smalltalk) e ho problemi a usare
UML dato che servirebbe la grafica ma se spedisco un post HTML con
degli attachment grafici come minimo mi linciate (e a ragione).
Quindi cerchero' di non usare una sintassi specifica. Almeno per il
momento.
Partiamo da un oggetto. Chiamiamolo "o". Ora o e' un nome che
semanticamente rappresenta un oggetto. Questo oggetto sara' una
istanza specifica di una classe. Chiamiamo la classe "T". In c++
potremmo scrivere "T *o=new T;". Fin qui tutto semplice.
Ora passiamo alla classe. Sappiamo che si chiama T. Ora in senso
puramente astratto tutto e' un oggetto. Quindi anche T e' un oggetto.
Questo non e' del tutto rappresentato in C++, quindi puo' "suonare
difficile". Ma provate ad immaginare di scrivere un compilatore o un
programma di CASE o qualche altro SW che manipoli i programmi o la
loro rappresentazione. Supponiamo che il vostro prodotto si chiami P e
che un utente lo stia usando per "manipolare" O. O e' un programma. Il
programma che l'utente sta scrivendo. E come tale possiede classi,
metodi, oggetti etc. Anche P e' un programma. Il programma che
l'utente usa. Ma dal vostro punto di vista, come programmatori di P, P
possiede classi, metodi, oggetti etc. Ovviamente state lavorando a due
livelli. Quando discutete di P con qualcuno dovete fare attenzione al
significato delle parole. Quando dite classe dovete assicurarvi che
sia chiaro se state parlando di una classe che fa parte del vostro
programma o se intendete una classe nel contesto dell'utente, che nel
vostro programma e' un oggetto. Ora supponiamo di estendere il
concetto: il vostro programma e' scritto in un linguaggio che supporta
la closure completa dei tipi. Quindi la classe di un oggetto e' a sua
volta un oggetto. Il vostro programma potenzialmente puo' manipolare
se stesso a run-time. O meglio puo' manipolare le classi stesse di cui
e' composto.
Torniamo al nostro esempio. T e' un nome. Il nome di un oggetto.
Questo oggetto si da il caso essere una classe. Come tale potra' avere
delle istanze. Per esempio o e' una istanza di T. Domanda: se T e' un
oggetto, allora T e' una istanza di una classe. Quale classe?
Chiamiamola "C". Ora C e' un nome. Il nome della classe di cui T e'
istanza. Ovviamente essendo C una classe potra' avere piu' istanze. In
un programma C++ potremmo avere codice come questo:
class Q {
};
class R {
};
class S {
};
class T {
};
...
Q *q=new Q;
R *r=new R;
S *s=new S;
T *t=new T;
T *u=new T;
T *v=new T;
T *z=new T;
Abbiamo che q,r,s,t,u,v e z sono nomi che fanno riferimento a istanze
specifiche di qualche classe. In particolare q, r e s si riferiscono a
istanze delle classi, rispettivamente Q, R e S. Invece t, u, v e z si
riferiscono a istanze diverse tutte della classe T. In C++ ci si ferma
qui. Nel nostro eventuale linguaggio OO "puro" avremo pero' che anche
Q, R, S e T sono oggetti e qiindi istanze di una classe. E
precisamente della classe C. Fino qui quasi semplice.
Se le classi sono a loro volta oggetti (e pertanto istanze di una
classe) e se C e' il nome della classe di cui sono istanze le mie
classi, allora posso anche dire che C, essendo una classe, e' un
oggetto, e pertanto e' istanza di una classe. Domanda (cruciale): di
quale classe e' istanza C?
Risposta che da un lato e' ovvia ma nello stesso tempo non e' banale
da capire concettualmente: C e' una istanza di C.
Ed ecco qui la nostra closure!
Prova a ragionarci sopra. Immaginati che C, inteso come classe,
possieda tutti i medodi e i membri che servono per manipolare le sue
istanze. Che pero' sono a loro volta classi.
Quindi eventuali data member di C come classe potrebbero essere:
container dei data member facenti parte della classe.
container dei metodi facenti parte della classe.
container delle classi base.
Ed eventuali metodi di C come classe potrebbero essere:
add a data member
add a method
add a base class
crea istanza
Nota soprattutto quest'ultimo. In un sistema OO puro tutte le azioni
sono dei metodi di qualche classe. E come tali invocati (in OO puro si
dice "spediti") ad una istanza di quella classe. Quindi in OO puro la
creazione di una istanza avviene chiamando un metodo di un oggetto.
Ovviamente sara' un metodo dell'oggetto che rappresenta la classe che
si vuole istanziare.
Questo e' il corrispondente del costruttore. Domanda: come faccio in
OO puro a rappresentare costruttori alternativi? Ovvero se esistono
tre modi di costruire una istanza di una classe, come li rappresento?
Se ci hai ragionato sopra abbastanza a lungo e hai capito come
funziona il meccanismo della closure la risposta arriva da se e
implica che quello che ho detto fin'ora si avvicina ad una soluzione
puremente OO ma ... non e' del tutto esatto. Manca un livello di
indirezione (quello che ti permette di avere le classi come
singleton).
Correggioamo di conseguenza il nostro esempio di cui sopra,
dimenticandoci del tutto il C++.
Ripartiamo dall'oggetto e ridiamo le definizioni aggiungendo qualche
cosa.
1) ogni oggetto e' un'istanza di una classe
2) esiste la classe "O" che rappresenta un oggetto generico
3) ogni classe e' un oggetto
4) esiste la classe "C" che rappresenta una classe generica
poi definiamo:
5) "o" e' una istanza di "T" (intesa come classe)
6) "T" (intesa come oggetto) e' una istanza (singleton) di "CT"
(intesa come classe)
7) "CT" (intesa come oggetto) e' una istanza di "C" (intesa come
classe)
a questo punto abbiamo per derivazione logica:
8) 1 and 2 -> ogni classe e' derivata (direttamente o indirettamente)
da "O" (intesa come classe)
9) 4 and 3 and 1 -> ogni classe le cui istanza sono classi e' derivata
(direttamente o indirettamente) da "C" (intesa come classe)
10) 5 and 8 -> "T" deriva da "O" (intese come classi)
11) 6 and 9 -> "CT" deriva da "C" (intese come classi)
12) 4 and 2 -> "C" deriva da "O" (intese come classi)
il che ci da, in linea di massima la nostra gerarchia di classi (ho
aggiunto qualche altra classe):
 O
 |\
 | \
 T  C
   /|\
  / | \
CT  CC CO
e ci da anche le nostre relazioni classe oggetto (rappresentate di
seguito con il nome della classe seguito dall'insieme delle sue
istanze, gli apici marcano i singleton):
T{o}
CT{T}'
CC{C}'
CO{O}'
C{CT,CC,CO}
Nota che tutte la classi che derivano da C, che sono le meta-classi
(ovvero le classi le cui istanze sono classi), generano solo
singleton.
Insomma, poche idee ma ben confuse!


 vista filosofico sarebbe un singleton).
Non mi trovo assolutamente d'accordo! Un singleton a parere mio risolve
altri problemi: le due soluzioni non sono intercambiabili: pensa al mio
caso: che senso potrebbe avere crearmi una classe singleton che incapsuli la
map di cui sopra, per poi avere che tutti i threadBody dovrebbero avere un
puntatore a tale unica istanza. Una map membro statico non è forse la
soluzione più naturale?
Insomma: tu dici che "le classi possono essere utilizzate un po' come delle
istanze di cui esiste un solo esemplare ma non credo che sia una soluzione
corretta", ma non è il corretto punto di vista. Un data member statico non è
una classe di cui *deve* esistere una sola istanza, è una classe che deve
avere un'associazione 1:n con un altra classe! A dire la verità, se la
classe A contiene un data member statico di classe B, nulla vieta di avere
altre istanze della classe B altrove nel programma!!!! Un singleton è la
risposta giusta *ad un altro problema* !!!
Ciao
Daniele.


Non molto. Supponi che tu lo possa sia dichiarare const che non const.
Fammi capire in quali contesti quel metodo puo' essere chiamato se
dichiarato in un modo ma non se dichiarato nell'altro.

Forse non hai notato che si parlava "in senso filosofico". E in senso
filosofico significa dal punto di vista OO puro. Nell'OO puro tutto,
ma proprio tutto e' un oggetto (e quindi un'istanza di classe).
Pertanto NON ESISTE nulla che non sia un oggetto. In particolare non
esiste il concetto di statico. Non esistono funzioni che non siano
metodi di una classe. Non esistono variabili che non siano membri di
una classe o locali ad un metodo. E ovviamente non esiste il concetto
di "static".
Chiedi che senso ha crearti una classe singleton che incapsuli la map
di cui sopra? Semplice: in senso filosofico e' l'ultimo modo. Inoltre
in un sistema OO puro qualla classe esiste gia': e' la metaclasse
della tua classe. Ovvero la classe la cui unica istanza (singleton) e'
l'oggetto che rappresenta la tua classe (in OO puro una classe e' un
oggetto).
Naturalmente non c'e' alcun bisogno che le tue istanze threadBody
mantengano un puntatore. Otterrano il puntatore semplicemente
chiamando il metodo corrispondente (che in C++ sarebbe un metodo
statico della loro classe mentre in un sistema OO puro sarebbe un
metodo della metaclasse).
Nel tuo esempio con le classi A e B, B e' la classe del tuo oggetto. A
e' la classe di B (che e' un oggetto a sua volta). B genera tutte le
istanze che vuoi. A ha una sola istanza: B. In un sistema OO puro,
tutti i membri "ordinari" di B restano membri di B. Quelli che in C++
sono costruttore, distruttore, new e delete di classe, e membri
statici, in un sistema OO puro (dove non esiste il concetto di const)
non sono altro che membri di A.
Vedi anche il mio altro post.


 ma proprio tutto e' un oggetto (e quindi un'istanza di classe).
Già, "Dire che tutto è un oggetto è come non dire niente"   [Stephanov]
Peccato ancora una volta che noi stiamo parlando di C++, un linguaggio
misto, e non di smalltalk, un linguaggio ad oggetti puro!
Intendiamoci, non che non apprezzi la teoria della OO, anzi, ne sono un
fervente sostenitore. Ma poichè il C++ è un linguaggio a due livelli (v.
l'ultima "C++ informer"), e possiamo utilizzare gli strumenti che il C++ ci
mette a disposizione per creare funzionalità che in altri linguaggi (ad un
livello) possono essere create solo "mettendo mano al compilatore", non vedo
perchè non approfittarne. Soprattutto perchè in questo caso (l'utilizzo di
un data member statico) non inficia riusabilità, manutenibilità e
estendibilità. Insomma, quando un design non inficia queste tre proprietà
che sono quelle che si prefigge la OO, vuol dire che siamo sulla strada
giusta. La strada giusta non si trova invece con la filosofia che non sia
sorretta da solide fondamenta pratiche!

 C{CT,CC,CO}
Ma non c'è qualche riferimento circolare? E' normale?
EMG


Non c'e' un riferimento circolare. C'e' una closure. Le classi sono
sia oggetti che generatori di oggetti. In un sistema OO puro un
oggetto che e' un'istanza di una classe contiene un riferimento
(puntatore) alla classe stessa. Ovvero all'oggetto che rappresenta la
sua classe (un po come in C++ dove un oggetto contiene un puntatore
alla vtable). Ricordati che in OO puro tutto e' un oggetto. Una classe
e' un oggetto. Un metodo (ovvero se vuoi il suo codice) e' un oggetto.
Persino il nome del metodo e' un oggetto (una stringa, ovvio).
Invento una sintassi (ma e' simile a quella del C++). Supponi di
essere nel contesto di un qualche metodo, non ci importa quale ne di
quale classe, e che esista una variabile (qualunque cosa sia nel
nostro linguaggio) che chiamiamo "o" e che fa riferimento ad una
istanza di una classe che chiamiamo T. E supponiamo che la classe che
chiamiamo T sia rappresentata da un oggetto che e' una istanza della
classe CT. Per ora fermiamoci qui. Immagina che nel codice del nostro
ipotetico metodo ci sia qualcosa come:
 o->m( 23 );
non siamo in C++, siamo nel nostro sistema OO puro. Domanda cosa
ricaviamo da quanto sopra? Possiamo ipotizzare che esista un metodo
della classe T chiamato "m" che accetta un intero come unico argomento
formale (oltre ovviamente al this). Cosa avviene a livello di codice
macchina? Usiamo il C e il C++ per spiegarci. Costruiamo il nostro
caso in C++:
class T {
public:
    virtual void m(int i);
};
...
T *o;
...
o->m( 23 );
traduciamo quanto sopra in C (il mangling e' parziale ed inventato):
struct T_obj;
struct T_vtbl {
    void (*m)(struct T_obj*this,int i);
};
struct T_obj {
    const struct T_vtbl *vtbl;
};
void m__T_v_pTi(int i);
const struct T_vtbl T_vtbl_here = { m__T_v_pTi };
...
T_obj *o;
...
(*(o->vtbl->m))(o,23);
il meccanismo e' semplice e anche abbastanza ottimizzato. Immaginiamo
ora un sistema OO puro. Per gestirlo devo estendere perecchio le
definizioni. Ci provo. Con una implementazione parzialissima e
incompleta e totalmente non ottimizzata e in una sistassi totalmente
inventata (quindi forse inconsistente):
Queste sono le interfaccie che ci interessano.
// (1)
// E' l'interfaccia base della gerarchia
Object {
    // definizione parziale.
    ObjectClass* class();
    System*system();
};
// (2)
// E' l'interfaccia della sub-gerarchia
// delle metaclassi.
Class: derives Object {
    // definizione parziale.
    ClassClass* class();
    Dictionary* methods();
};
// (3)
// E' l'interfaccia dell'oggetto che rappresenta
// la classe Object. L'interfaccia di tale classe
// e' quella in (1).
ObjectClass: derives Class {
    // definizione parziale.
    Class* class();
};
// (4)
// E' l'interfaccia dell'oggetto che rappresenta
// la classe Class. L'interfaccia di tale classe
// e' quella in (2).
ClassClass: derives Class {
    // definizione parziale.
    Class* class();
};
// (4)
// E' un'interfaccia definita dall'utente
T: derives Object {
    // definizione parziale.
    ClassT* class();
    void m( int );
};
// (5)
// E' l'interfaccia dell'oggetto che rappresenta
// la classe ClassT. L'interfaccia di tale classe
// e' quella in (4).
ClassT: derives Object {
    // definizione parziale.
    ClassT* class();
};
Ora il nostro codice:
 o->m( 23 );
viene tradotto con questo pseudocodice:
o->class()->methods()->get("m")->execute(o,23);
ovviamente e' uno pseudocodice perche' ciascuna chiamata a sua volta
puo' essere "tradotta" allo stesso modo.
In ogni sistema che suppora una closure completa il sistema puo'
descrivere e modificare se stesso. Ovviamente in una implementazione
reale c'e' un punto in cui il nocciolo del sistema deve essere
realizzato all'esterno. Se voglio scrivere un compilatore, ho bisogno
di un compilatore preesistente. Un sistema OO puro comprende se stesso
e il suo compilatore in closure complete. Tale sistema, una volta
creato, puo' compilare se stesso modificandosi (in certi casi anche in
runtime). Ma ovviamente la prima implementazione deve essere fatta "da
fuori".
L'invocazione dei metodi puo' avvenire secondo il pseudocodice
suddetto. E avverrebbe cosi' se la classe T e il codice "o->m( 23 );"
fossero eseguiti a livello di interprete. Ovviamente durante la
compilazione la catena di chiamate "logiche" descritta viene
ricondotta a delle chiamate di sistema pre-compilate. Di solito
scritte in C o assembler. Se non fosse cosi' avremmo una ricorsione
infinita quando la chiamata o->m si traduce, come visto, in una catena
che inizia con la chiamate o->class la quale ovviamente si traduce a
sua volta in una catena che inizia con ... o->class. Ovvio che la VERA
traduzione in assembler avviene in maniera diversa. Per esempio il
metodo class non viene invocato ma viene direttamente eseguita la sua
logica. Che e' quella di recuperare il puntatore alla classe dalla
struttura dell'oggetto. Notate infatti che le definizioni delle
interfacce non prevedono "membri" ma solo metodi. Un membro in OO puro
non esiste: e' solo un modo "breve" per indicare una coppia di metodi
correlati (uno con semantica get e uno con semantica set). Se la
nostra T in C++ fosse stata:
class T {
public:
    virtual void m(int i);
    long l;
};
in OO puro avremmo una delle due:
T: derives Object {
    ClassT* class();
    void m( int );
    long get_l();
    long set_l( long );
};
T: derives Object {
    ClassT* class();
    void m( int );
    long* l();
};
e sarebbero tutte virtuali, ovviamente.


 sorretta da solide fondamenta pratiche!
Sono d'accordo. Ma nessuno ti critica per il tuo codice. Semplicemente
si era colta l'occasione posta dalla tua domanda per analizzare la
purezza del supporto OO del C++. Il che non significa criticare il C++
come strumento di sviluppo (a piu' livelli, come dici tu). Significa
semplicemente dire che il C++ supporta la OO solo parzialmente. Che
questo supporto sia "sufficiente" per lavorare e' fuori discussione.
Cio' non toglie nulla al fatto che sia filosoficamente parziale. E il
fatto che sia parziale non toglie nulla al fatto che sia potente e
usabile in quasi tutti i contesti pratici.


 usabile in quasi tutti i contesti pratici.
Ho capito.
Però, se non vi dispiace, vorrei lo stesso un consiglio sul mio codice.
Insomma, il poter mettere la parola chiave "const" di fianco al metodo
statico che dicevo io, non sarebbe d'aiuto per la migliore comprensione del
codice (in fondo è a questo che serve il "const")?

 codice (in fondo è a questo che serve il "const")?
Spero che non ti offenderai se ti dico che non hai capito a cosa serve
il const.
Il const non serve alla migliore comprensione del codice.
Nel C (e nella parte C del C++) serve a migliorare il funzionamento
dell'ottimizzatore. Ovvero se scrivo:
int sub( const double *p, int i );
int f( double d )
{
    int i,j;
    i=(int)d;
    j=sub(&d,i);
    j+=(int)d;
    return j;
}
allora l'ottimizzatore puo' ridefinire il tutto in maniera piu'
efficiente cosi':
int f( double d )
{
    int _a;
    _a=(int)d;
    _a+=sub(&d,_a);
    return _a;
}
perche' "sa" che d non e' cambiato dalla chiamata a sub. Se il
puntatore non fosse stato costante, non avrebbe potuto farlo.
In c++ la cosa si estende ai membri non statici di classe.
L'ottimizzatore sa che chiamando un membro non statico dichiarato
const, lo "stato" della classe non cambia. Quindi puo' ottimizzare il
codice che fa accesso a membri dato della classe sia prima che dopo la
chiamata al metodo di conseguenza. Cosi' come in f ottimizza un
accesso a d fatto prima e dopo una funzione che lui sa non lo puo'
modificare.
Questo e' lo scopo di const.
Perche' non si applica al caso di metodi statici con il concetto di
"non modifica i membri statici e non chiama i metodi statici non
const" e' semplice. Perche' non c'e' nessun modo di garantirlo.
I membri statici possono essere pubblici o non pubblici. Quelli non
pubblici possono essere modificabili da metodi statici pubblici.
Entrambe i tipi possono essere modificati da metodi non statici.
Supponi di avere:
int f();
class C {
private:
    static int j;
    static int i;
public:
    static int m(int v) { j=v; return ++i; }
    static int s() { f(); return i+j; } // eventuale static
};
Secondo te c'e' qualche motivo per cui C::s non possa richiamare f? O
esiste una qualche sintassi sensata che possa dire al compilatore che
f, che non fa parte della classe, non puo' essere chiamata
dall'interno di C::s?
Supponi che f, magari in un altro modulo, sia definita cosi':
int f()
{
    return C::m(3);
}
Capisci cosa intendo.
Se il tuo scopo e' "la migliore comprensione del codice" puoi sempre
usare i due meccanismi che il C++ mette a disposizione a questo
preciso scopo.


perche' "sa" che d non e' cambiato dalla chiamata a sub.
Falso (purtroppo). La funzione sub e' autorizzata a
modificare il valore di d (anche se per farlo deve
prima forzare il puntatore con const_cast) e il compilatore
non ha il permesso di ignorare questa possibilita'.
Se d fosse const allora il compilatore potrebbe essere
sicuro che il valore non e' cambiato (ma neanche f
riuscirebbe a cambiarlo) e se "sub" ci provasse con
const_cast allora dal naso di chi lancia il programma
potrebbero uscire dei demoni.
HTH


 potrebbero uscire dei demoni.
Nope. Vedi sopra. Se cosi' fosse const sarebbe quasi inutile.


 commentato.
Questa lista l'hai redatta tu, immagino!
Prima cosa non è vero che l'espressività "si ottiene con i commenti". Anzi
dovrebbe essere vero l'opposto: cioè che inserisci i commenti solo dove il
codice non è autoesplicativo, e in effetti, considerata la pigrizia dei
programmatori a documentare i contesti di chiamata, le precondizioni e le
postcondizioni mediante commenti, una delle cose più utili di un linguaggio
usato per progetti di ampia dimensione è probabilmente l'espressività delle
interfacce degli oggetti. Il poter scrivere
double A::f( const& B, double x )
{
    assert( x >= 0 );
    ...
    assert( result >= 0 );
    return result:
}
mi sembra chiarisca in maniera esaudiente come va usato tale metodo.
Probabilmente in Eiffel le cose sarebbero ancora più chiare, ma chi usa
Smalltalk dubito possa apprezzare il design by contract ;-)
Ritengo comunque che una lista come la tua possa venire redatta solo
considerando il campo di applicazione del linguaggio. Se è vero che chi
realizza videogiochi considera ottimizzazioni dell'ordine dei cicli di clok,
chi si occupa di grandi progetti solitamente preferisce un linguaggio
altamente espressivo e che eviti il maggior numero di errori di codifica.
Pertanto per te la 4) può essere l'ultima forza, ma in altri contesti
potrebbe essere la prima.
Per tornare al const, è vero che è utilizzato dal compilatore per eventuali
ottimizzazioni, ma se questa è la cosa più importante per te, può non
esserlo per gli altri, che la vedono anche come un ottimizzazione per
autodocumentare il codice e per eliminare una fonte di errori a
compile-time.

 wrote in message
news:DGlf6.9912$092.1...@twister1.tin.it...


Nope. Vedi sopra. Se cosi' fosse const sarebbe quasi inutile.
Beh... non e' inutile per un sacco di altre ragioni...
comunque non aiuta molto l'ottimizzatore (sicuramente
non lo aiutano i puntatori o reference a const).


 l'oggetto (a meno che l'oggetto sia dichiarato const).
A questo punto devo certamente sottolineare: *PURTROPPO*


Mi si pone una domanda fondamentale: cosa sarebbe 'sto OO puro? Dove e'
codificato? Esiste uno standard? Temo che alle ultime due domande non
esista una risposta comunemente accettata.
In realta' esistono linguaggi che associano ad ogni classe una "class
instance" o meta-classe, che tendenzialmente funge da aggancio a
meccanismi di riflessione. Per la scarsa esperienza che ho, mi pare che
i linguaggi che supportano le meta-classi sono anche linguaggi ad
ereditarieta' singola.
Da qui a dire che le meta-classi sono un elemento dell'OO puro...
Ciao,
Nicola

 codice (in fondo è a questo che serve il "const")?
In C++ l'unico modo per "rendere" il concetto che esprimi e' incapsulare
i membri dato statici in una nuova classe, della quale le funzioni
membro statiche precedenti diventano funzioni membro normali (const o
meno). Francamente non ho mai sentito bisogno di qualcosa di piu'. Tieni
presente che in genere const e non const servono a delineare piu'
precisamente l'interfaccia della classe. Cosa un metodo faccia al suo
interno non sono affari di chi lo usa e se ritieni che debbano esserlo
e' probabilmente venuto il momento di rivedere l'organizzazione in
classi del tuo codice.
Ciao,
Nicola

 dell'ottimizzatore. Ovvero se scrivo:
Spero non ti offenda tu se ti dico che secondo me Daniele ha capito
meglio di te. Nella programmazione di oggi, salvo alcuni settori
specifici e di nicchia, ha molta piu' importanza il modo in cui il
codice comunica il proprio significato ad altri programmatori che non
limare qualche picosecondo, soprattutto prima ancora di aver effettuato
misure prestazionali.
Ciao,
Nicola

 ancora in C non si parlava gran che di "aiutare" il programmatore).
Sei sicuro? A me risulta che const il C l'abbia "ereditato" all'indietro
dal C++.
Ciao,
Nicola

 wrote in message
news:3A7EA128...@divalsim.it...


 wrote in message
news:3A7EA434...@divalsim.it...


 wrote in message
news:3A7EA300...@divalsim.it...


Infatti se segui il thread, ho ammesso il mio errore.
Vogliamo quotare correttamente!?!?! Grazzzzie...
Luc.

Sono assolutamente d'accordo.
Ciao,
Nicola