Newsgroup: it.comp.lang.c++
Titolo: Polimorfismo

Ciao! Per favore mi spiegate cos'è il polimorfismo in c++? Mi fate un
banale esempio? Vorrei imparare l'oop.
Grazie!
Toto'



Supponi di avere
Uccello che deriva da Animale e
Cane che deriva da Animale;
Allora puoi fare una cosa del tipo:
Animale* uccello = new Ucello;
Animale* cane = new Cane;
a questo punto:
uccello->parla();
e
cane->parla();
avranno due comportamenti diversi  anche se apparentemente
stai chiamando il metodo parla della classe Animale.
Ciao
Gaetano.
-- 
Posted from 
dell-01.mm.eutelsat.org
 [194.214.173.17] 
via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 stai chiamando il metodo parla della classe Animale.
magari se ci metti esplicitamente a conoscenza che la classe Animale ha un
metodo parla() il ragionamento funziona :)
ciao :: xaero

stai chiamando il metodo parla della classe Animale.
Non e' necessariamente vero.
Perche' la tua affermazione sia vera, il metodo parla() di
Animale deve essere virtuale, altrimenti uccello e cane
parleranno sempre come animali generici.
-- 
Andrea Laforgia - walkietalkie(at)
libero.it

 parleranno sempre come animali generici.
Ecco cosa sbagliavo da una vita...... era da anni che cercavo 
di usare sto benedetto polimorfismo e non ci ero mai riuscito.
Ho anche scordato di dire, permettimelo, che se Animale alloca
della memoria dynamicamente devo fare anche il distruttore virtuale, 
altrimenti rischio di avere dei memory leak
Ovviamente nel distruttore devo deallocarla, per far si che anche questa
mia ultima affermazione sia vera.
:-)


altrimenti rischio di avere dei memory leak
Il problema non e' se la classe base alloca memoria
dinamicamente, il problema e' se la alloca la classe figlia.
In realta', le classi madri dovrebbero avere sempre il
distruttore virtuale (in teoria dovrebbero essere classi
astratte, quindi con metodi virtuali puri).


 astratte, quindi con metodi virtuali puri).
Be posso non essere daccordo con te sul fatto che il distruttore
deve essere sempre virtuale ? Metti che sono geloso della mia
bella classe e non voglio che nessuno la estenda :-)
a parte questo colpo di egoismo sai anche tu che ci sono altri
casi in cui non e' obbligatorio, anzi meglio non mettere nulla di
virtuale (ogni funzione virtuale mi aggiunge un paio di byte alla
vera occupazione in memoria di una classe ad esempio).


vera occupazione in memoria di una classe ad esempio).
Ribadico: una gerarchia di classi in cui non c'e'
polimorfismo non ha molto senso, secondo me.


 polimorfismo non ha molto senso, secondo me.
Se c'e' una gerarchia appunto, ma alcune volte non c'e'.



Scusa la domanda, ma sai cosa è un oggetto (istanza di una classe, che è
il concetto di base dell'OOP)? Te lo chiedo perchè la domanda che hai
fatto è un pò ambigua, e nei post degli altri lo davano per scontato.
Ciao,
Cecco

 dinamicamente, il problema e' se la alloca la classe figlia.
A dire il vero, il problema è che chiamare delete su un oggetto di tipo
derivato tramite puntatore a classe base è "undefined behaviour" se il
distruttore non è virtuale. Probabilmente, nella maggioranza delle
implementazioni (forse tutte) quello che accade è che viene chiamato
soltanto il distruttore della class base, ma ciò non toglie che secondo lo
standard si tratta pur sempre di "undefined behaviour".
Max

 standalone ?
In questo thread stiamo parlando di polimorfismo, ergo di
ereditarieta'.
-- 
Posted from  [80.105.34.80] 


 essere virtuale.
Tutti avete capito? Mi raccomando deve essere una cosa quasi
istintiva, non scordate mai virtual in un distruttore.
Anche questa volta caro il mio Laforgia hai ragione.
Ciao
Gaetano.
PS: C'e' una proposta  in tal senso di far  si che i distruttori siano
virtual di default,
      senza il bisogno di specificarlo ogni volta? O magari l'introduzione
della nuova
      parolina novirtual da anteporre ai distruttori se si vuole che lo 0.1%
delle volte
      non lo siano ?
-- 
Posted from 
dell-01.mm.eutelsat.org
 [194.214.173.17] 


 istintiva, non scordate mai virtual in un distruttore.
"Raccomandazione 67 
 Ogni classe avente funzioni virtuali, o utilizzata come 
 classe base in una gerarchia di derivazione, deve dichiarare 
 il distruttore come virtual. Negli altri casi, commentate 
 opportunamente l'header della classe, cosi' che l'introduzione 
 di classi derivate coincida con la modifica del distruttore in 
 virtual." [Carlo Pescio - C++, manuale di stile]
"Ovviamente non esiste alcun motivo per cui un distruttore 
 non possa essere virtuale, anzi in presenza di funzioni virtuali 
 e` sempre bene che anche il distruttore lo sia (al 99,9% e` 
 necessario, negli altri casi e` una garanzia per il funzionamento 
 del programma, soprattutto in previsione di future revisioni)"
 [Paolo Marotta - C++, una panoramica sul linguaggio, pag.].
"Forgetting to make a destructor virtual is an
 insidious bug because it often doesn’t directly affect the 
 behavior of your program, but it can quietly introduce a 
 memory leak. Also, the fact that some destruction is occurring 
 can further mask the problem."
 [Bruce Eckel - Thinking in C++ 2nd ed., pag. 667]
etc... etc... etc...
-- 
Posted from  [80.105.34.80] 


 
Item 14: Make sure base classes have virtual destructor.
[Scott Meyers - Effective C++ Second Edition, pag 59]
nello stesso item (pag 61)
    "If a class does not contain any virtual functions, that is
     often an indication that is not meant to be used as a base
     class. When a class is not intended to be used as a base
     class, making the destructor virtual is usually a bad idea.
     [...]
     The bottom line is that gratuitously declaring all destructor
     virtual is just as wrong as never declaring them virtual. In
     fact, many people summarize the situation this way: declare 
     a virtual destructor in a class if and only if that class contains
     at least one virtual function.
    This is a good rule, one that works most of the time, but
    unfortunately, it is possible to get bitten by the non virtual
    destructor problem even in the absence of virtual functions".
Ricordo anche l' Item 50 dello stesso libro.
Ciao
Gaetano.
 
-- 
Posted from 
dell-01.mm.eutelsat.org
 [194.214.173.17] 


 vera occupazione in memoria di una classe ad esempio).
Se non metti NULLA di virtuale risparmi qualche byte. Se anche una sola funzione
è virtuale non risparmi nulla. Non è vero che ogni funzione virtuale aumenta la
dimensione della classe. Solo la prima. Se una qualunque funzione è virtuale è
evidente che la classe verrà ereditata. E a questo punto il distruttore deve
essere virtuale anch'esso (al punto che al comitato si discute se renderlo
virtuale anche se non lo dichiari tale, quando la classe contiene una qualunque
funzione virtuale).
--
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

      class. 
Ti stoppo subito.
Noi siamo partiti dal polimorfismo, non dalla costruzione
di classi e se si parla di polimorfismo si parla,
necessariamente, di classi base e classi derivate, e se
si parla di classi base e classi derivate, si parla di
distruttori virtuali.
Io sono d'accordo sul fatto che se si progetta una classe
che non prevede derivazioni (credo che Java, per es., per
questo scopo abbia una keyword apposita) sia irrilevante[*]
avere o meno un distruttore virtuale.
Il concetto e' che, secondo me, e' difficile sapere a priori
se la propria classe avra' o meno dei figli.
Per sicurezza, le si impone un distruttore virtuale.
[*] non capisco perche' Meyers giudichi una "bad idea" fornire
una classe di distruttore virtuale anche laddove non sia
strettamente necessario. Con "bad idea", si intende generalmente
qualcosa che porta ad errori e il distruttore virtuale non capisco 
a che genere di errori possa condurre.
-- 
Posted from  [80.105.34.80] 


       non lo siano ?
L'ho già sentita ma credo che non verrà introdotta. Non è una vera proposta.
Solo una risposta all'unica obiezione che ha qualche senso all'introduzione
automatica del distruttore virtuale obbligatorio per le classi che hanno
funzioni virtuali.


 Se la classe non può essere derivata o può essere derivata solo privatamente,
Come si puo' fare in modo che da una classe non si possa derivare ? 
o che si possa derivare solo privatamente ?
-- 
Posted from  [80.105.34.80] 


     destructor problem even in the absence of virtual functions".
Come dice Scott solo nelle classi concrete e che non dovranno essere derivate e
che non contengono funzioni virtuali ha senso dichiarare il distruttore non
vrtuale. Scott dice anche che la regola che lui propone non e' sicura. Infatti
l'assenza di funzioni virtuali non rende una classe intrinsecamente non
derivabile. Quindi se è vero che tutte le classi che contengono funzioni
virtuali dovrebbero avere il distruttore virtuale, anche alcune classi che NON
contengono funzioni virtuli potrebbero necessitare di distruttore virtuale.


 a che genere di errori possa condurre.
class Point {
public:
     Point(short int xCoord, short int yCoord);
     ~Point();
private:
    short int x,y;
};
Quanto pensi che occupi questa classe in memoria ?
E se avesse il distruttor virtuale ?
Hai presente il pattern "Fly Weight"?
C'e' qualche campanello che sta suonando?
Ciao
Gaetano.
-- 
Posted from 
dell-01.mm.eutelsat.org
 [194.214.173.17] 


 o che si possa derivare solo privatamente ?
Non ne ho idea.
Ciao,
Nicola

 Solo quando nessuna delle classi contiene una funzione virtuale.
Mica e' assolutamente vero! Se non ho funzioni virtuali posso estendere
una classe e non usare il polimorfismo (uso di funzioni virtual) e
avere dei leakage:
template <class T>
class Array {
    public:
        Array();
        ~Array();
    private:
        std::vector<T> data;
};
class NamedArray : public Array<T> {
        NamedArray(const std::string& name);
        ...
    private:
        std::string name;
};
se ora usi la delete su un puntatore ad Array che in realta'
sta puntando a NamedArray ottieni che la stringa che contiene
NamedArray non viene deallocata.
In generale dire "Se ci sono funzioni virtuali allora devo fare il
distrutttore
virtuale altrimenti no" e' sbagliato.
Si suggerisce per far capire che una classe e' una classe da trattare come
base
per una gerarchia dichiarare il distruttore virtuale puro.


 a che genere di errori possa condurre.
Infatti Scott non è del tutto corretto in questa affermazione.
Non solo è abbastanza limitato il caso in cui lui ammette l'assenza di
costruttore virtuale (vedi mio altro messaggio che include il caso di
ereditarietà privata).
Ma chiama "bad idea" l'uso del distruttore virtuale in maniere troppo generica.
Esiste un solo caso in cui il distruttore virtuale è una "bad idea". Quando la
classe è concreta, non deve essere ereditata, non ha nessuna funzione virtuale,
non contiene oggetti complessi, ha una dimensione totale relativamente piccola
ed è destinata ad essere inserita in containers di dimensioni molto grosse
(praticamente stiamo parlando di un piccolo POD arricchito da metodi non
virtuali).
Inoltre è generalmente preferibile che questo genere di classi siano confinate a
bassissimo livello di astrazione, possibilmente accedibili solo da poche TU
(massimo un modulo, in termini OOA/OOD).


 o che si possa derivare solo privatamente ?
Scrivendolo bello grosso nella documentazione relativa alla classe e confinando
la classe in una sola TU o al massimo in un modulo. Ovvero non rendendo la
classe pubblica in un header che definisce l'interfaccia esterna del modulo in
questione. Dichiarandola privatamente all'interno di un'altra classe che la usa
solo correttamente. Dichiarando i costruttori e i distruttori privati e
dichirando esplicitamente le classi friend e scrivendo queste correttamente.
etc.


 virtuali).
Quindi l'incidenza e' solo dal punto di vista prestazionale.
Temevo di peggio :)


 errore logico.
Io capovolgerei il discorso: se una classe non contiene distruttore
virtuale derivare da questa e' un errore logico.
Ciao,
Nicola

 E se avesse il distruttor virtuale ?
Vedi risposta ad Andrea Ferro.
-- 
Posted from  [80.105.34.80] 


 per una gerarchia dichiarare il distruttore virtuale puro.
Solo se la classe è astratta. Ovvero se non ha bisogno di codice nel distruttore
e se, ovviamente, non è concreta.


 Temevo di peggio :)
Non solo. Se la classe è effettivamente un POD (per esempio se corrisponde ad un
record di un file) o se il suo uso è molto "massivo" hai ben più che una caduta
di prestazioni: hai un non funzionamento dovuto alla non corrispondenza dei dati
o all'uso spropositato della memoria (che diventa disco). Un conto è una caduta
di prestazioni del tot %, un altro è passare di colpo da alcuni secondi per
l'esecuzione di un comando a parecchi minuti o ore!


 nessuna delle classi contiene una funzione virtuale."
Io interpreto:
( ( Solo quando la classe base è ereditata privatamente ) oppure ( Solo
quando la classe base e' non ereditata) )
ed inoltre
( Solo quando nessuna delle classi contiene una funzione virtuale).
Essendo della stessa opinione sulla prima riga ho citato solo la seconda.
Ciao
Gaetano.


 virtuale derivare da questa e' un errore logico.
dovresti aggiungere "pubblicamente" dopo "derivare".


 Max
Ad esempio, questo "undefined behaviour" si manifesta molto spesso in un 
crash dell'applicazione in presenza di ereditarieta' multipla...
In generale, se una classe ha almeno un metodo virtuale, e' bene che abbia
anche il distruttore virtuale. (Non costa nulla e ci evita problemi in 
futuro).
Se abbiamo il sospetto che la classe possa essere derivata in un futuro,
non sarebbe certo un eccesso di prudenza dichiararne comunque il distrutture
virtuale.
(E meno che questo non si traduca in un costo aggiuntivo, pensa
a una classe che contenga solo un byte e di cui vengano create qualche
milione di istanze, lo spreco di memoria per il distruttore virtuale 
sarebbe enorme)
Un altra domanda da porsi, sarebbe invece: E' onesto derivare pubblicamente 
da una classe il cui distruttore NON e' virtuale ?
(Mi riferisco, ad esempio, a una classe che non possiamo modificare, e di 
cui quindi non possiamo rendere virtuale il distruttore)
Anche qui la questione va affrontata "cum grano salis".
In generale una cosa del genere potrebbe essere pericolosa, ma in qualche
caso puo' essere comoda.
Supponiamo, ad esempio, di avere una Interfaccia I (classe base con tutti 
metodi virtuali puri) e una classe concreta C, senza metodi virtuali.
Noi vorremmo adattare I a C, usando una nuova classe D, derivata 
pubblicamente da entrambe, che implementi I in termini di C, ma che anche 
si comporti a tutti gli effetti come una C in certi contesti.
Vorremmo per esempio, poterla passare a funzioni che si aspettano un 
reference a C, o usarla in generale in contesti dove la relazione "is a" C 
valga (insomma, supponiamo di avere i nostri motivi per NON incapsulare C 
dentro D usandola come membro dato).
Tutto questo e' fattibile, fintanto che non proviamo a distruggere D facendo
una delete su un suo puntatore a C. Ma, vista la concezione di D, questa
eventualita' dovrebbe essere alquanto remota...
(forse mi sono dilungato un po' troppo...)
Saluti,
Fabio
-- 
Posted from 
flopiano.mm.eutelsat.org
 [194.214.173.28] 


 a che genere di errori possa condurre.
Penso che sia sostanzialmente per gli argomenti esposti sopra: definire
il distruttore virtuale indica a chi legge che la classe e' stata
progettata per essere derivata, mentre magari non e' vero.
Ciao,
Nicola

 dovresti aggiungere "pubblicamente" dopo "derivare".
Ci sono casi in cui questo e' pericoloso anche per derivazione privata,
ad esempio una chiamata virtuale puo' ritornare un puntatore ad una
classe derivata anche se la derivazione e' privata.
Ciao,
Nicola

 funzione virtuale).
Letteralmente parlando la *classe* cresce per ogni funzione virtuale che
aggiungi; sono d'accordo che le sue istanze non crescono dopo l'aggiunta
della prima funzione virtuale :-)
Ciao,
Nicola

 classe derivata anche se la derivazione e' privata.
Pienamente daccordo ( mi ha fregato la pausa "pranzo"  :-) )
Ciao
Gaetano.


 Vedi risposta ad Andrea Ferro.
Quale ?
Ripeto:
<< Quanto pensi che occupi questa classe in memoria ?
E se avesse il distruttor virtuale ?
Hai presente il pattern "Fly Weight"? >>
Ciao
Gaetano.
-- 
Posted from 
dell-01.mm.eutelsat.org
 [194.214.173.17] 


 (massimo un modulo, in termini OOA/OOD).
Gia'. Una classe Data ad esempio. Ma va...
Ciao,
Nicola

 Ripeto:
Sono io che ripeto: vedi risposta ad A. Ferro.
-- 
Posted from  [80.105.34.80] 


hai un non funzionamento dovuto alla non corrispondenza dei dati
Non riesco a capire a cosa ti riferisci, 
mi faresti un esempio pratico ?


 };
Immagino che doGetPositiveInt() sia in realta' doGetInt()
nell'implementazione di getPositiveInt() (BadDerive() e'
ovviamente BadDerived).
Questo e' il metodo di gestire le post-condizioni
nelle classi figlie, che il contratto con la classe madre 
deve garantire ?


 essere derivata.
Ma segnalarlo a chi ? il compilatore comunque ti consente di
derivare da una classe del genere (mentre in Java, usando "final", 
no, giusto ?).


 deve garantire ?
Esatto. Ho scritto il codice un po' troppo in fretta...
Ciao,
Nicola

 no, giusto ?).
A chi sviluppa con te o mantiene il tuo codice. Cercare di esprimere
chiaramente le proprie intenzioni nel codice e' fondamentale anche se si
sviluppa da soli.
Ciao,
Nicola

 sviluppa da soli.
Ah ok, segnalarlo ad altri umani :)
Quello che volevo dire e' che non mi sembra il modo di ricostruire
in C++ l'uso del "final" di Java.  Il compilatore non e' informato
delle tue intenzioni, quindi non puo' proteggerti.


 meccanismo di riuso esageratamente sopravvalutato.
Se ti sentisse l'architetto della VCL :)


 no, giusto ?).
Questo č il punto. Il C++ non mette al riparo da usi scorretti e dalla
violazione del typesystem. L'uso ammesso per una classe non č l'insieme delle
cose che si possono fare senza che il compilatore generi un errore. L'uso
ammesso per una classe č quello specificato nella sua documentazione.
Se disegni una classe con l'idea che non debba essere derivata o che non debba
essere derivata pubblicamente il C++ ti mette a disposizione alcuni modi per
rendere la cosa piů difficile, ma non č compito suo impedire ad un utente
"smaliziato" di aggirare il sistema e comportarsi diversamente da quello che chi
ha disegnato la classe prevedeva. L'uso ammesso per una classe deve essere
specificato chiaramente nella sua documentazione. Un uso diverso da quello
documentato deve essere considerato "non supportato".
Inoltre dire che per segnalare che una classe non deve essere ereditata si
dichiara il distruttore non virtuale č una prassi terribile. Se una classe non
deve essere ereditata questo deve essere espressamente indicato nella sua
documentazione. Non nella sua definizione in C++!


 classe derivata anche se la derivazione e' privata.
Il fatto che venga ritornato un puntatore alla derivata non è pericoloso. Semmai
è pericoloso se viene ritornato un puntatore alla base. Se la derivazione è
privata questo non avviene neppure tramite chiamata a virtuale (a parte il fatto
che si era detto che se esiste una funzione virtuale, anche il distruttore deve
essere virtuale). A meno che tu non scriva un membro pubblico nella classe
derivata che lo fa o non renda pubblicamente visibile un metodo privatamente
ereditato che lo fa (ma questa è una stupidata che fai tu nell'implementazione
della classe derivata, non un problema logico nella derivazione privata).


 documentazione. Non nella sua definizione in C++!
Il fatto che il codice di una classe non sostituisca la sua
documentazione e' indubbio. Resta il fatto che *ogni* elemento della
classe suddetta *deve* essere li' per un motivo, e questo vale anche per
la dichiarazione virtual del distruttore. Chi codifica sulla della base
del "Forse, chissa', in futuro magari..." e' meglio che cambi mestiere.
Se e' vero che la documentazione di una classe deve far testo rispetto
alla scelta di derivare o meno da essa, in assenza della dichiarazione
virtuale del distruttore non deve neanche sfiorarci il dubbio se
derivare o no, a meno che la documentazione della classe stessa non
spieghi perche' derivare e' possibile/ragionevole (e francamente direi
che sono pochi i casi in cui una situazione simile puo' avverarsi).
Nel 2001 il codice lo si scrive piu' per i colleghi (o se stessi tra
qualche mese), che non per il computer. Il principio della minima
sorpresa ed il Rasoio di Occam dovrebbero a mio avviso costituire le
regole fondamentali per chi sviluppo, anche riguardo al mettere o
togliere un "virtual".
Ciao,
Nicola

 Se ti sentisse l'architetto della VCL :)
Per questo mi arrabbio con i sostenitori dell'OO pura: perche' correre
con le stringhe legate insieme? A me piace il C++ perche' mi mette a
disposizione un insieme di strumenti che a me paiono tutti utili e dopo
qualche anno di esperienza non sono piu' disposto a rinunciarvi.
Certo che in assenza di template, overloading, ridefinizione di
operatori ed ereditarieta' multipla, che altro puoi fare?
Ciao,
Nicola

 mi faresti un esempio pratico ?
La frase si riferiva all'uso dei POD aventi un mappaggio esterno (file binario,
per esempio) che possono essere arricchiti con metodi non virtuali ma non con
metodi virtuali altrimenti cambia la loro immagine in memoria.


 wrote in message
news:3BC44C9C...@divalsim.it...

Idealmente chi sviluppa con te l'header lo include e basta. Non lo legge. Per
usare la tua classe legge la relativa documentazione. Ovviamente se la
documentazione è nell'header stesso allora lo leggerà. Ma leggerà appunto la
documentazione, non la dichiarazione della classe.


 rappresentano valori di grandezze).
Che guarda caso sono classi di piccole dimensioni, fatte per non essere derivate
(se non al limite privatamente) e prive di funzioni virtuali.


 della classe derivata, non un problema logico nella derivazione privata).
L'assegnamento di un'istanza di una classe derivata privatamente ad un
puntatore alla classe base puo' essere utile per impedire
all'utilizzatore di fare affidamento sul tipo effettivo dell'oggetto
puntato, ad esempio tramite dynamic_cast. Questo puo' costituire un
elemento di sicurezza ad esempio nell'utilizzo di plug-in.
Sono d'accordo che il distruttore deve essere dichiarato virtual,
semplicemente intendevo dire che la derivazione privata non e' una
garanzia che le cose funzionino correttamente se tale dichiarazione non
c'e'.
Tale garanzia si puo' avere invece, come avevo scritto altrove,
dichiarando il distruttore della classe base protected, in modo da
impedire che un'istanza della classe derivata possa essere distrutta
attraverso un puntatore alla classe base.
Ciao,
Nicola

 del "Forse, chissa', in futuro magari..." e' meglio che cambi mestiere.
Huh ? secondo me e' l'esatto contrario.
Chi programma non puo' ignorare come verra' usato il proprio codice
in futuro.
Uno dei punti di forza del polimorfismo, per esempio, e' proprio
quello che si puo' pensare in termini di "forse, chissa', in futuro magari..."
senza che in futuro il codice possa essere modificato.
Ma la riusabilita' non era uno dei concetti fondamentali del C++ e 
dell'OOP in generale ? e la riusabilita' non e' forse legata
anche agli utilizzi futuri del codice ?


 operatori ed ereditarieta' multipla, che altro puoi fare?
Questo e' vero.


 ( Solo quando nessuna delle classi contiene una funzione virtuale).
Se la classe non è fatta per essere ereditata la frase "nessuna delle classi" si
riferisce ovviamente a questa sola. E credo che su questo siamo d'accordo.
Se la classe è ereditata privatamente la frase "nessuna delle classi" si
riferisce a questa e a quelle che da essa ereditano privatamente.
Mi sembrava chiaro. Provo a riformularla (alla luce anche dei commenti fatti da
altri):
Una classe appartiene alla categoria PNVD (possible non virtual destructor)
delle classi per cui ha senso non dichiarare un distruttore virtuale solo se la
classe non contiene funzioni virtuali E non deriva pubblicamente da alcuna
classe E se deriva non pubblicamente le classi base sono esse stesse
appartenenti alla categoria PNVD E è pensata per non essere derivata se non in
maniera non pubblica e da classi a loro volta appartenenti alla categoria PNVD E
il tutto è esplicitamente e dettagliatamente documentato nelle istruzioni d'uso
della classe E le istruzioni d'uso della classe indicano che qualunque uso al di
fuori di queste regole non è supportato dal design della classe per cui anche se
funziona potrebbe non funzionare in una futura implementazione.
Una classe appartiene alla categoria CNVD (convenient non virtual destructor)
delle classi per cui conviene non dichiarare un distruttore virtuale solo se la
classe appartiene alla categoria PNDV E ha una dimensione relativamente piccola
E non è escluso a priori che venga instanziata molteplici volte all'interno di
un container di grandi dimensioni.
IMO


 (se non al limite privatamente) e prive di funzioni virtuali.
Discutibile. Le stringhe sono tipicamente classi con value semantics,
anche se magari non vengono usate in questo modo per preoccupazioni
relative all'efficienza.
Idealmente persino le matrici nell'ambito del calcolo matriciale sono
classi con value semantics.
Ciao,
Nicola

 dentro D usandola come membro dato).
Se ci sono motivi come questi, IMO, o la classe C è disegnata male o ti sfugge
qualche cosa.


 anche agli utilizzi futuri del codice ?
Certo, ma la riusabilita' impone che si ragioni in termini di: "Caro
futuro sviluppatore, puoi utilizzare la mia classe in questo, quello e
quell'altro modo.", non di "Forse, chissa'".
Se il riuso deve essere qualcosa di piu' che un caso fortuito (se non
addirittura un disastro, come nel caso del missile Ariane) deve essere
anticipato correttamente (e pagato, in termini di sforzo e di denaro).
Bisogna poi distinguere come usi l'ereditarieta' per ottenere il riuso:
se definisci delle classi di interfaccia in modo che le classi che ne
derivi possano sfruttare meccanismi che usano quelle interfaccie, bene;
se l'approccio e' del tipo "Cavoli, questa classe fa quaaaasi quel che
mi serve, aspetta che derivo, cosi' la riuso" non ci siamo per niente.
Secondo me una gerarchia di classi ben disegnata nasce quasi tutta dalla
testa del suo ideatore, tutt'al piu' con qualche buco qua e la da
riempire in seguito. Difficilmente alle generazioni di sottoclassi
corrispondono anche generazioni di sviluppatori.
Ciao,
Nicola

 progettata per essere derivata, mentre magari non e' vero.
Resto dell'idea che l'uso ammesso di una classe debba essere documentato
all'esterno della dichiarazione/definizione della classe stessa.


 un container di grandi dimensioni.
Se per Convenient intendi solo dal punto di vista prestazionale, sono
d'accordo; se intendi anche in termini di chiarezza del codice, no.
Ciao,
Nicola

 Questo e' vero.
Del gruppo omonimo...
Ciao,
Elio

 togliere un "virtual".
Concordo. Anche se in teoria questo è sempre stato vero!


 anche agli utilizzi futuri del codice ?
Quello che Nicola voleva dire non è che la classe da cui oggi non derivi non
debba essere resa derivabile per un uso futuro. Intendeva dire che progettare
una classe senza sapere se da questa sarà possibile derivare o meno è sbagliato.
Quando progetti una classe, se non ci sono motivi precisi contrari, la dovresti
progettare per essere derivabile. Quindi prevedere un uso futuro diverso da
quello attuale.
L'errore non starebbe quindi nel presupporre che la classe sarà usata in modi
oggi non prevedibili ma nel non decidere se questo sarà o meno possibile.


 attraverso un puntatore alla classe base.
Il che però presuppone che la classe base non sia una concreta instanziabile di
per se, ma sia destinata, appunto, ad essere derivata.


 all'esterno della dichiarazione/definizione della classe stessa.
Le due cose non sono in contrasto, anzi dovrebbero essere obbligatorie
entrambe; solo che senza il codice il programma non gira (o gira meglio,
a seconda dei casi :-), senza la documentazione ahime' si.
Ciao,
Nicola

 corrispondono anche generazioni di sviluppatori.
tranne il caso dei framwork, ma come sappiamo tutti un buon framework ancora ha
da vedere la luce del sole.


 oggi non prevedibili ma nel non decidere se questo sarà o meno possibile.
Esatto. La scelta deve essere esplicita. Questo tra l'altro vale a
livello strategico: scrivere codice riusabile costa di piu' che non
scrivere codice non riusabile, anche a parita' di qualita' del codice
stesso.
Ciao,
Nicola

 wrote in message
news:3BC4656A...@divalsim.it...

Sono entrambe esempi di classi fatte per non essere derivate (se non al limite
privatamente) e prive di funzioni virtuali.
L'unico lato discutibile è sul fatto che siano di piccole dimensioni.
Però è un fatto che o l'implementazione non è fatta per value semantic oppure lo
è ma viene passato un proxy che alloca separatamente la vera struttura dati
(normalmente con reference count) e pertanto la classe in se "diventa" di
piccole dimensioni. (poi c'e' anche il caso in cui viene mantenuta la value
semantic e la classe resta di dimensioni enormi, ma a questo punto il discorso
di risparmiare sul virtual destructor per motivi di memoria o di efficienza
nelle prestazioni fa alquanto ridere).


 implementazione della "delega" dei metodi.
Uno dei pochi casi in cui la pigrizia del programmatore puo' essere
deleteria :-)
Ciao,
Nicola

 da vedere la luce del sole.
Diciamo che un framework avra' piu' buchi, ma che proprio per questo
dovranno essere stati pensati ancor meglio che se fossero pieni.
Ciao,
Nicola

 funziona potrebbe non funzionare in una futura implementazione.
Alla fine qui tutti sappiamo quando o no fare un distruttore virtuale ma e'
dannatamente impossibile buttare giu una regola. L'unica regola
da seguire a mio modesto parere e' quella del "Buon Padre di Famiglia".
Ciao
Gateano.
-- 
Posted from 
dell-01.mm.eutelsat.org
 [194.214.173.17] 


 nelle prestazioni fa alquanto ridere).
In realta' penso che l'omissione della dichiarazione virtuale del
distruttore "per motivi di efficienza" vada giustificata nei fatti, come
tutti i casi in cui si tira in ballo l'efficienza.
Ciao,
Nicola

 meccanismo di riuso esageratamente sopravvalutato.
Le classi della libreria standard non sono ereditabili (pubblicamente) perchè
sono disegnate per avere value semantic (e di fatto hanno value semantic). Sono
bulding blocks. In una applicazione vera e di una certa dimensione i container
di STD non compaiono nell'interfaccia pubblica di un modulo (tranne un modulo
che a sua volta è templated e si basa quindi sul concetto dei generici, come
detto dopo) ma piuttosto all'interno delle interfaccie private dei moduli o
nelle loro implementazioni.
Inoltre stai parlando di classi che non si basano sul discorso del polimorfismo
e relativi aspetti della OO classica ma che si basano invece sul concetto di
"generics" (template il C++ parlance). In questo contesto il "riuso" si basa
sulla pura sintassi delle operazioni. Pensa al concetto di iteratore.
L'"interfaccia" di un iteratore non è definita in termini di metodi (lo sarebbe
in linguaggi tipo Smalltalk in cui la semantica di una classe e la sintassi del
linguaggio non sono separati come in C++) ma piuttosto in termini di "sintassi"
di alcune operazioni ammesse. Un iteratore non è definito dicendo, per esempio,
che deve supportare operator* in un certo modo. Ma solo che deve essere valido
scrivere "*i".
C'e' una grossa differenza. La differenza fra il polimorfismo e i generici.
L'ereditarietà non è esagaratamente sopravvalutata, IMO. E' erratamente usata in
contesti in cui ci sono alternative migliori. Ma questo vale anche per i
generici!


 operatori ed ereditarieta' multipla, che altro puoi fare?
Scrivere Linux? <g>


 disegnata.
Sempre Meyers fa il seguente ragionamento:
1) Una classe astratta viene fatta per essere usata come base
2) E siccome e' una classe base (qui tutti siamo daccordo che deve
    avere il distruttore virtuale) deve avere il distruttore virtuale.
3) La presenza di un metodo virtuale puro fa si che una classe
    sia astratta.
allora dice la soluzione e' semplice:
Se stai facendo una classe che deve essere usata anche come base
(del resto gli hai messo il distruttore virtuale) allora il distruttore
fallo virtuale puro e lo implementi comunque.
Se il distruttore non deve fare nulla invece che pagare l'overhead di
una chiamata ad un metodo vuoto allora (per legarsi ad un altro thread)
lo facciamo anche virtuale. Alla fine la classe ideale per essere una classe
base deve
essere la seguente:
class PBC {    //Perfect Base Class
public:
    inline virtual ~PBC() = 0;
};
PBC::~PBC() { }
Ciao
Gaetano.
PS: Finalmente facendo gli estremisti ( non so se avete notato ma
ultimamente
      sto provocando con asserzioni che lasciano poco spazio) si genera
qualche
      thread interessante.


> reference a C,
[ discorso su operatori snipped ]
In realta' mi riferivo in generale al principio di sostituibilita', cioe' 
alla necessita' di poter usare la classe D al posto di C in maniera 
trasparente.
Saluti,
Fabio 
-- 
Posted from 
flopiano.mm.eutelsat.org
 [194.214.173.28] 


 quell'altro modo.", non di "Forse, chissa'".
Ah, allora eravamo gia' d'accordo da prima ;)


 stesso.
In teoria costa qualche cosa di più nel breve termine e costa molto di meno nel
lungo termine. E' lo scopo dello scrivere codice riusabile. In teoria. In
pratica la cosa è vera solo se sono vere molte altre condizioni al contorno
(documentazione, supporto, incentivi al riutilizzo, pubblicizzazione della
code-base, insomma tutte le attività correlate alla manutenzione del codice
riutilizzabile all'esterno del progetto in cui è stato inizialmente
implementato).


 fallo virtuale puro e lo implementi comunque.
Concordo con te e con Meyers ma non vedo come si leghi al discorso della classe
C che č fatta per non essere derivata.


 class optimization (cfr. librerie Boost, 
www.boost.org
)
Mi sembra di ricordare che le policy di Alexandrescu prevedano l'uso di private
inheritance. Io parlavo di public inheritance.
Non so cosa facciano le boost (le conosco poco) ma facendo un discorso generale
anche l'empty-base-class-optimization dovrebbe far uso di private inheritance.
Vedi anche 
http://www.gotw.ca/publications/mill07.htm


 a seconda dei casi :-), senza la documentazione ahime' si.
A parte il caso in cui il programma gira meglio senza il codice (caso che in
genere è più frequente proprio quando manca la documentazione) c'è da dire che,
almeno in teoria, sviluppare codice non dovrebbe avere come scopo solo il far
girare un programma ma anche l'evitare che qualcun'altro nella stessa azienda
debba sviluppare codice simile in futuro. E, almeno in teoria, mentre il primo
scopo è quello che provoca un maggior guadagno nel breve termine, è il secondo
scopo quello che ha maggior valore aggiunto.


 in maniera trasparente.
La classe std::vector è un template che fa parte della STL e che come saprai ha
come elemento di genericità il fatto di rispondere ad un certo numero di
"requirements" che sono conosiuti come "container requirements" e come "sequence
requirements". L'uso di std::vector (o meglio la sua sostituibilità con altre
classi) ha senso proprio in questi termini. Ovvero laddove puoi sostituire
un'altra classe che risponde agli stessi requirements. Per esempio std::list o
std::deque, che come ben sai non derivano da std::vector.
Pertanto quello che suppongo tu voglia fare è un template NetVector che risponda
ai requirements dei container e delle sequence (o addirittura anche a quelli più
stringenti degli std::vector) in modo da poterlo usare laddove useresti un
vector. Ma se guardi bene (salvo codice scritto da te) ogni uso di vector
prevede di fatto non tanto l'uso di un vector ma piuttosto l'uso di un
container. Ovvero puoi sostituire deque o list al posto di vector (e ueste non
derivano da vector!) fatte salve considerazioni specifiche (per esempio list ha
efficienza di accesso diversa e non fornisceiteratori random).
Poniti questa domanda: se scrivessi NetVector in maniera che faccia tutto quello
che fa vector ma senza derivare da questo, avrei problemi di sostituibilità? La
risposta per quanto riguarda la STL è no. Per quanto riguarda funzioni scritte
da te, dipende da come le hai scritte. Se le hai scritte in maniera che
richiedano specificatamente un vector, il problema è tuo!
Quindi io ti suggerisco di ereditare privatamente da vector e di rendere
pubblici tutti i membri del vector che sono indipendenti dallo stesso (che poi
sono tutti tranne costruttori, distruttori e operatori di copia). Costruzione
distruzione e operatori di copia li devi comunque riscrivere anche se erediti
pubblicamente, quindi non vedo il problema.
Teoricamente questo è un containment (come se dichirassi un membro di tipo
vector, ridichiarassi tutti i metodi e li implementassi per delega). Solo che
nel caso delle STL lavorare per delega e implementare tutti i casi ti obbliga a
conoscere alcuni dettagli dell'implementazione specifica delle STL che usi. Con
questo metodo (derivazione privata e pubblicazione dei metodi non specifici
della classe base) riesci a fare quello che vuoi molto più facilmente e in
maniera portabile.


 scopo quello che ha maggior valore aggiunto.
Sono assolutamente d'accordo, salvo che la seconda metodologia ha un
costo "up front" che va riconosciuto, accettato e messo a budget.
Altrimenti le cose non possono funzionare.
Ciao,
Nicola

 implementato).
Io ne sono convinto, ma il costo maggiore iniziale deve essere
accettato. Tra l'altro l'Extreme Programming, cosi' popolare oggidi', si
fonda sostanzialmente sulla negazione di questo punto di vista.
Ciao,
Nicola

 wrote in message
news:3BC55656...@divalsim.it...

Si. Ma da quello che ho visto l'XP funzionicchia se applicato fino in
fondo e solo su linguaggi come lo Smalltalk e (in misura minore) il
Python.


 C che è fatta per non essere derivata.
Ho sgarrato il quoting.
