Newsgroup: it.comp.lang.c++
Titolo: Accesso a membri protected

Salve a tutti. C'è una cosa che non capisco riguardo ai membri
protected, per esempio:
class A{
	protected:
	int dato;
};
class B:public A {
	void set_a(A& oggettoa, int a1) {
		oggettoa.dato = a1;
	}
};
int main() { }
Questo non compila perché il dato a1 risulta "protetto" nel contesto
della funzione "set_a".
Ma le classi derivate come B non dovrebbero avere accesso ai membri
protected delle classe base?
Sembra che valga solo per membri propri dell'oggetto ma non per membri
di altri oggetti, come nell'esempio...
In un caso simile bisogna per forza rendere public "dato" o in
alternativa definire la classe B come friend di A?
O c'è una soluzione più "pulita"?
Grazie

 O c'č una soluzione piů "pulita"?
La soluzione pulita č mettere in B un metodo che setta il proprio "dato"
e quindi usare questo metodo in set_a.
E.

 e quindi usare questo metodo in set_a.
Ok, grazie.
Nel programma vero e proprio ci sono svariati "dati" membro della
classe e non mi va di scrivermi tutti i get/set :-)
(tra l'altro non c'è bisogno di un controllo sul valore settato).
La rendo friend e via...
Ciao

 viene in mente :-)
Se non funzionasse cosě, una classe qualsiasi derivata da A potrebbe
modificare i membri protetti della componente A di un oggetto di tipo B.
Max

 La rendo friend e via...
No. Non farlo. Probabilmente C++ non è il linguaggio che fa per te. Per 
certi versi C++ è un linguaggio per paranoici: l'assunzione è che chi 
può modificare qualcosa può fotterlo; più enti possono modificare cose 
'non indispensabili', più è probabile che il tuo programma esploda o 
dia inizio ad una guerra termonucleare globale.
Da non paranoico di dico: se hai una classe di cui non ti frega 
restringere l'accesso, falla struct e lasciala pubblica. Almeno hai 
presente che quella è una classe aperta al mondo e che ci devi stare 
attento.
Se parti con i friend, finisci che a forza di farti amici tutti ti 
trovi nella situazione di cui sopra ma avendo il tutto molto più 
incasinato.
A questo punto io personalmente ti suggerirei:
1. ti armi di un buon editor che supporti snippets e che renda 
aggiungere setter e getter banale
2. ti armi di un buon IDE che faccia quanto sopra
3. ti dai all'uso di macro. quando hai finito qualcuno ti dirà che è 
una cattiva idea e con un semplice search e replace metti a posto 
tutto.
#define RW_ATTRIBUTE(name, type) \
    private: type name; \
    public: \
        type get_ ## name() { return name; }\
        void set_ ## name(type v) { name = v; }
class Foo {
    RW_ATTRIBUTE(foo, int)
    RW_ATTRIBUTE(boo, double)
};
-- 
The most important thing in the kitchen is the waste paper basket and 
it needs to be centrally located.
Donald Knuth

 };
Bello. Molto bello. Se mi serve lo tengo in considerazione.
L'unica sbavatura è che bisogna metterlo in coda alla definizione delle 
classi, dopo è tutto pubblico. Non credo che sia possibile porre 
rimedio a ciò.
-- 
Articolo 33 della Costituzione italiana: L'arte e la scienza sono 
libere e libero ne è l'insegnamento

 a ciò.
Forse, per rimanere sul "safe side", bisognerebbe rimettere "private:" 
alla fine della macro.
E.

 "private:" alla fine della macro.
Quoto. Il problema è che 'dopo' la macro non ci potrebbe stare un altro 
access-specifier
RW_ATTRIBUTE(...)
protected:
...
Darebbe errore. Non sono problemi facilmente gestibili e in effetti lo 
considero un po' un 'trucco sporco'. Tuttavia in fase di sviluppo 
rapido, quando uno prova tante cose etc etc etc è IMHO utile comunque. 
Poi generalmente quando una classe ha una faccia 'stabile', li levo e 
ci metto il codice vero.
Alla fine IMHO la cosa migliore è la convenzione di metterli in fondo e 
basta.
-- 
I think computer viruses should count as life. I think it says 
something about human nature that the only form of life we have created 
so far is purely destructive. We've created life in our own image.
Stephen Hawking

 access-specifier
Forse basterebbe scambiare la parte private: con la parte public: nella 
macro.
E.

 nella macro.
Geniale. Hai ragione.
-- 
"Python makes us extremely productive, and makes maintaining a large 
and rapidly evolving codebase relatively simple." (Mark Shuttleworth)

 porre rimedio a ciò.
Vero. E' un prezzo relativamente piccolo da pagare, dopo tutto. :)
In fondo spesso anche gli IDE che generano roba del genere mettono 
tutto in un dato posto che fa comodo a loro.
L'idea sostanzialmente viene dalle funzioni ruby attr_reader 
attr_writer che a partire da il nome dell'attributo generano quanto di 
dovere.
Un'altra idea che mi è venuta in questo momento, ma non ho mai usato 
sarebbe questa qui (dopo). Ovviamente è una bozza, bisognerebbe fare 
eventuali specializzazioni per i puntatori, aggiungere la gestione di 
assegnamento da tipi diversi (quando ha senso etc etc). Diciamo che 
potrebbe essere uno scheletro. Diciamo anche che non mi sembra farina 
del mio sacco... credo di avere già visto qualcosa del genere, anche se 
non ricordo dove (e probabilmente in più di un posto).
#include <iostream>
template<typename Type>
class RW_Accessor {
  Type value_;
public:
  RW_Accessor(Type v) : value_(v){}
  RW_Accessor(const RW_Accessor& other) : value_(other.value){}
  Type operator()() const {
    return value_;
  }
  Type operator()(Type v) {
    value_ = v;
  }
};
struct A {
  RW_Accessor<int> i;
  RW_Accessor<double> f;
  A(int iv, double fv) : i(iv), f(fv) {
    std::cout << i() << f() << std::endl;
  }
};
int main (int argc, char const *argv[])
{
  A a(3, 5);
  a.i = 8;
  return 0;
}
-- 
Nevertheless, I consider OOP as an aspect of programming in the large; 
that is, as an aspect that logically follows programming in the small 
and requires sound knowledge of procedural programming.
Niklaus Wirth

 Darebbe errore.
Perche'? Il seguente esempio compila con tutti i compilatori che ho
qui (Comeau, g++ 3.4.5 e 4.2.1, VC++ 2005):
class A {
  public:
  protected:
  private:
  public:
};
int main() {
}
Ciao,
Nicola
P.S. Ho notato che spesso i sorgenti della libreria standard
contengono sequenze di access specifier.

 sarebbe questa qui (dopo). 
Sì, questo è interessante. E però sta anche a significare che in prima 
istanza posso usare dati pubblici, se poi ho bisogno di accederci 
tramite metodi posso sempre farlo successivamente e in maniera 
trasparente all'utente della classe (sfruttando appunto il tuo esempio).
E.

 tuo esempio).
Esatto. E' quello cui stavo pensando. Il problema sono che i 'getter' 
hanno comunque un cambiamento di sintassi. A meno che, forse definendo 
un cast automatico 'a Type' si potrebbe pure scrivere solo
foo.x;
Interessante. Ma dove sta la fregatura?
-- 
We will perhaps eventually be writing only small modules which are 
identified by name as they are used to build larger ones, so that 
devices like indentation, rather than delimiters, might become feasible 
for expressing local structure in the source language. (Donald E. 
Knuth)

 qui (Comeau, g++ 3.4.5 e 4.2.1, VC++ 2005):
Questo è interessante. Mi sono tuttavia andato a vedere la grammatica 
cf  contenuta nello standard e a meno che non abbia battuto la testa 
non 'dovrebbe' funzionare.
Posso benissimo essermi incasinato io, comunque.
-- 
I decry the current tendency to seek patents on algorithms. There are 
better ways to earn a living than to prevent other people from making 
use of one's contributions to computer science.
Donald Knuth

 Posso benissimo essermi incasinato io, comunque.
sembrerebbe :-) La grammatica contiene:
class-specifier:
    class-head { member-specification opt }
member-specification:
    member-declaration member-specification opt
    access-specifier : member-specification opt
Ciao,
Nicola

 sembrerebbe :-)
Eh. Non ho visto l'opt.
-- 
If you optimize everything, you will always be unhappy.
Donald Knuth

 aggiungere setter e getter banale
Ma se aggiungo tutti i set/get, alla fine il risultato sarà che TUTTE
le classi potrebbero modificare i dati e incasinarli, come se fossero
pubblici.
Cioé non vedo il vantaggio di usare get / set se non c'è necessità di
controllare limiti o validità del dato in entrata.
Nel caso pratico, questi dati dovrebbero essere sostanzialmente
"privati", nel senso che non interessano agli "utenti" e non devono
essere modificati.
Mi serve però che le classi derivate possano invece accedervi e
accedere anche alla base di altri oggetti della stessa classe
derivata.
Usando i get/set apro la porta a "tutti", col friend solo a qualcuno
(la classe derivata), mi sembra preferibile...

controllare limiti o validità del dato in entrata.
Il fatto è che la classe la progetti oggi e non sai come evolverà la
situazione in futuro.

 (la classe derivata), mi sembra preferibile...
Non sono d'accordo. Dovere usare molti friend indica un qualche 
problema nel design.
Tipicamente la situazione da te descritta IMHO indica appunto un 
problema di design. Cioè pubblico è quello che tutti possono/devono 
accedere. Se hai troppe cose che devono mettere le mani sotto il cofano 
stai cercando guai.
-- 
My duty as a teacher is to train, educate future programmers.
Niklaus Wirth

giro. No. Non mi piace.
Secondo me, il fatto che la modifica nella classe padre non debba
ripercuotersi in giro prescinde dal "protected" e ricade nelle regole
di buon design. Quello che "proteggi" è sottoposto a un contratto né
più né meno di quello che rendi pubblico.

 più né meno di quello che rendi pubblico.
Appunto. Il punto è che meno roba ho public e più sono libero di 
cambiare gli internals. Nel caso di protected agli occhi dei figli è 
come se fosse pubblico: ovvero, tutto quello che è protected può non 
essere liberamente modificabile, poichè potrebbe essere usato qui e la.
IMHO stiamo dicendo la stessa cosa, comunque.


cambiare gli internals. 
Ok, però una classe che non espone niente non è utile a nessuno :-)
Piuttosto, direi che se devo scegliere tra public e protected, laddove
non serva che i metodi get/set siano visibili all'esterno, li rendo
protected. Questa è la regola che ti insegna, ad esempio, il manuale
di scrittura dei componenti di Borland distribuito con Delphi e C++
Builder. In quest'ultimo in particolare (nel primo sono keyword del
linguaggio a tutti gli effetti) c'è l'estensione __property che
consente di creare delle property (analoghe a quelle Python). La
gerarchia VCL prevede delle classi base di tipo TCustomXXX
(TCustomButton, TCustomPanel, ecc..) che racchiudono i comportamenti
base dei componenti e che non sono istanziabili direttamente. Il
consiglio che la guida dà è che, ogni qual volta si costruisce una
classe TCustomQUALCOSA, i getter/setter siano protetti, il che è
piuttosto ragionevole, essendo poi resi pubblici dalle classi
derivate.

 Ok, però una classe che non espone niente non è utile a nessuno
Un conto è esporre "comportamenti" un conto è esporre "variabili".
Ok, ci sono casi in cui le due cose collassano, ma capita spesso che 
non lo sia. Oggi come oggi nel mio codice ci sono pochissime 
SetQualcosa/GetQualcosa. Tendo ad avere pochi classi che fanno molto, e 
una libreria in simil C con handle opachi che devono essere passati. 
Look minimale ma che ha una sua ragion d'essere.
Insomma, sono certo di essermi spiegato malissimo, ma mi piacciono 
moltissimo le black box.


Un conto è esporre "comportamenti" un conto è esporre "variabili".
Non si tratta propriamente di variabili, ma di proprietà, che possono
mappare o meno variabili. Con i getter/setter di Delphi e C++ Builder,
ad esempio, tu puoi mappare direttamente il valore della variabile
membro, oppure stabilire delle regole di lettura (che potrebbero
andare a pescare i dati da chissà dove); idem per la scrittura.
Quindi, alla fine, stai comunque esponendo un comportamento. Le
property di Delphi e C++ Builder mi piacciono molto per questo,
proprio perché non rendi troppo fragile il contratto con la classe
madre.

madre.
Questa storia dei "contratti" andrebbe ridimensionata, o quanto meno 
spiegata. Ne leggo spesso, ma devo ancora capire cosa si intende. Da 
una funzione, io, non capisco nessun "contratto". Quello lo capisco al 
massimo dalla documentazione, se mai esiste. Ma in C++ una funzione, a 
me, non dice molto. Una funzione del genere che contratto "espone":
void SetPapero(const Papero& quack);
rispetto a:
class blabla
{
public:
 Papero quack;
 ..
};
Devo mantenere codice con qualche KB di Set/Get dirette su variabili, e 
dopo svariati anni mi sono rotto di mantere quel codice. Secondo me è 
la teoria paranoica di sottofondo del C++ che è sbagliata. Proteggere 
perché chi utilizza la classe madre potrebbe essere un mascalzone e 
fare chissà che se avesse un accesso diretto alle variabili.
Attenzione, io non sono contrario a prescindere ai Get/Set, ne alla 
programmazione che espone "comportamenti" e neppure alla programmazione 
che espone variabili. Dico solo che ho a che fare con codice in cui i 
Set/Get sono stati fatti senza pensare seriamente a quel che si faceva.
Ultimamente ho avuto a che fare con FxCop, un analizzatore di sintassi 
per dotnet. Ho trovato irritante che segnalasse come errore l'accesso 
ad una variabile tramite una funzione invece che attraverso una 
property. Ma mi accorgo che sto divagando, e quindi mi fermo.


 una property. Ma mi accorgo che sto divagando, e quindi mi fermo.
Brr..
-- 
Your highness, when I said that you are like a stream of bat's piss, I 
only mean that you shine out like a shaft of gold when all around it is 
dark

void SetPapero(const Papero& quack);
Hai davvero la pretesa che ti si risponda seriamente, quando fai
l'esempio di un metodo "SetPapero"?

sintatticamente diverso da una chiamata di metodo.
Se tu sapessi cosa sono le __property di C++ Builder, sapresti che
questo non è necessariamente vero.

  Brr..
Ecco, tutti d'accordo qui? :)
--*PaN!*
 
-- 
I'm using an evaluation license of nemo since 220 days.
You should really try it!
http://www.malcom-mac.com/nemo

 questo non è necessariamente vero.
Non ho la più pallida idea di cosa siano e non mi risulta che siano
parte del C++ standard. Per inciso qualche giorno fa ho postato qua in
zona un abbozzo di un accessor templatico che più o meno fa sto mestiere
(mancavano un paio di dettagli, ma IMHO funge), potrebbero essere una
cosa simile. 
-- 
cc = callcc {|cc| cc.call cc}; cc.call cc

 l'esempio di un metodo "SetPapero"?
Sono un professionista e mi rivolgo a professionisti. Un professionista 
sa leggere il "vero" contenuto informativo di una frase scherzosa senza 
troppi problemi.
SetPapero ->
1) Funzione che "setta"
2) Che cosa setta? Una proprietà di tipo Papero
3) Non è un tipo base
4) A frucugliare ci potrebbero essere problemi di temporanei creati dal 
compilatore proprio perché non è un tipo base
Ti trovi meglio con esempi del tipo: SetFoo, SetOggettoParticolare? Il 
contenuto informativo era uguale, ma meno divertente. Killami che fai 
prima.


 Brr..
La cosa più inquitante però è che dato un exe tiri fuori il codice con 
una semplicità disarmante. Ogni volta che lo vedo mi spavento.


 uso posso dire che la sua utilità si è rivelata scarsa.
Perchè non usi <cassert>?
E.

 però se i parametri sono 5 o 6 il codice torna ad essere illeggibile.
Il modo "giusto" di gestire questo tipo di situazioni e' introdurre un
tipo apposta:
class IntDa1A1234 {
    int val;
  public:
    IntDa1A1234(int v) : val(v) {
      assert(val >= 1 && val <= 1234);
    }
    operator int() { return val; }
};
A maggior ragione quando i compilatori implementeranno la keyword
explicit per gli operatori di conversione. A seconda dei casi si puo'
rimpolpare la classe, cosi' come trasformarla in template.
Ciao,
Nicola

 tipo apposta:
Non ci avevo pensato, mi metto l'idea in un cassetto per il futuro. Per 
ora non gestisco la cosa così ma tendevo ad un più banale codice di 
errore.
bool SetAddressTCP(const std::string& host, int port)
{
  if ( /*FallitoTest host*/ )
     return false;
  if (port <= 1024)
     return false;
  //bla-bla
  return true;
}
Questo però lo facevo ieri. Oggi me ne frego del test e se uno mi da un 
indirizzo farlocco la connessione fallirà e pace. Oggi sono per la via 
del: "chi configura il software sa quel che fa, se non lo sa che usi i 
valori di default scelti da me".


 Perchè non usi <cassert>?
Per usare la keyword non standard __assume del compilatore Microsoft
#ifdef DEBUG
# define quack_assert(e)   ( assert(e) )
#else
# define quack_assert(e)   ( __assume(e) )
#endif
Serve per dire all'ottimizzatore del compilatore che di lì non si 
passerà e/o che l'espressione sarà sempre vera.
Però visto che uso, e consiglio di usare sempre, il flag di 
compilazione: "Buffer Security Check", tranne nei casi in cui si tratti 
software con 10 anni di onorato servizio senza mai un bug, la cosa era 
diventata ridicola. Uso un assert non portabile, per risparmiare un 
bagigio secondo, quando di default uso una compilazione non ottimizzata 
al massimo delle prestazioni possibili.
Ultimamente sono tornato ad usare <cassert>.
+++
Mentre scrivevo questo post con MSDN sotto ho visto che sono comparse 
le keyword non standard _ReadBarrier, _WriteBarrier, _ReadWriteBarrier. 
Viviamo in un mondo difficile. Su internet ci sono anche gli esempi con 
gli onnipresenti singleton e i motivi per cui sono state introdotte 
queste keyword. Viviamo in un mondo molto difficile.


 passerà e/o che l'espressione sarà sempre vera.
Ma l'assert di <cassert>, se compili con la macro NDEBUG disattivata, ti 
esclude il codice dalla compilazione. In particolare il codice dentro 
l'assert non deve avere effetti collaterali, in modo da poter essere 
tolto del tutto. Dunque il costo di un assert (in versione release) è 
zero tondo.
E.

 esclude il codice dalla compilazione.
Appunto si "limita" ad escludere il codice. Con la keyword non standard 
dico, anzi posso dire, al compilatore che di lì non ci passo proprio. 
L'esempio tipico è:
switch(qualcosa)
{
  case 0:
    break;
  case 1:
    break;
  case 3:
    printf("Non dovevo passare di qui.\n");
    __assume(0);
    break;
}
Il compilatore (microsoft) non genera il codice per il caso 3.
Usando la assert stardard il codice diventerebbe "semplicemente":
switch(qualcosa)
{
  case 0:
    break;
  case 1:
    break;
  case 3:
    printf("Non dovevo passare di qui.\n");
    break;
}
Capisco che sono dettagli esoterici per il 99.99% del programmatori.


 questo non è necessariamente vero.
Non conosco il dialetto borland di C++ (e sinceramente non saprei 
nemmeno dire se quello di cui parli è una feature a livello di 
linguaggio -- per cui è corretto parlare di dialetto -- oppure altro).
Comunque qualche giorno fa avevo fatto un acrocchio che permetteva in 
buona sostanza di avere le property senza cambiare la sintassi (usando 
template, per cui pure in modo piuttosto efficiente).
-- 
This series of books is affectionately dedicated to the Type 650 
computer once installed at Case Institute of Technology, in remembrance 
of many pleasant evenings.

 Capisco che sono dettagli esoterici per il 99.99% del programmatori.
Non mi pare. E' un problema noto a chi maneggia ottimizzatori e/o 
analizzatori statici.
Specie negli analizzatori statici ci sono molti progetti di ricerca che 
sono in grado di provare determinate proprietà ma hanno bisogno che il 
codice sia 'annotato' a mano. Ovvero che il programmatore dia 'dritte' 
al programma. E non sono cose molto diverse da quella __assume().
Va anche detto che in generale i tool che hanno bisogno di annotazioni 
manuali non sono il massimo della vita, poichè chiaramente sono 
relativamente costosi da usare con codice vecchio (che va annotato a 
parte).
Immagino che avere questo supporto nel compilatore possa essere una 
cosa comoda. Loro ovviamente lo usano in un certo senso, ma nessuno 
vieterebbe di usarlo in un altro senso.
Noi per dire utilizzavamo le assert. Il nostro analizzatore è 
relativamente furbo per cui conosce la semantica di tale espressione. 
In particolare sa che dopo l'assert può mettere nel database di fatti 
noti il fatto che da quel punto in poi la condizione nel corpo 
dell'assert vale. Infatti *se* la computazione va avanti, la condizione 
vale (se non va avanti, amen, si gestisce diversamente).
-- 
Software development is technical activity conducted by human beings.
Niklaus Wirth

 furbo per cui conosce la semantica di tale espressione. 
Interessante. Il compilatore MS non fa queste cose. Ne fa altre, ma non 
queste. Tutta roba complessa da usare comunque. Va bene su un progetto 
stabile, ma io lavoro da sempre sull'orlo del precipizio di una 
consegna.


 consegna.
Beh, il nostro aggeggio no di certo. Al di la del fatto che non è finito
(e che lo stanno riscrivendo) si tratta di chiamarlo su un sorgente e
lui ti trova determinate classi di errori. Punto. Intervento manuale 0
(poi si tratta di correggere gli errori, certo).


 (poi si tratta di correggere gli errori, certo).
Che dire, complimenti. Anzi, auguri. Tutta roba complessa.


 l'ottimizzatore non ottimizza.
Direi che hai centrato uno dei mali dell'informatica contemporanea.
Com'era quella del tizio con un martello?
Ciao,
Nicola

 Direi che hai centrato uno dei mali dell'informatica contemporanea.
Secondo me però questo è il sintomo. Il male è considerare, e molti 
dirigenti in europa fanno, il software qualcosa che qualsiasi pirla può 
fare a prescindere dalla complessità. Nel mondo dell'automazione spesso 
ho visto considerare "serio" l'hardware, e "non serio" il software. Un 
problema storico probabilmente. Personalmente ho risolto cambiando 
settore.
Rimane però per me il mistero del non avere mai visto la figura del 
tutor. Non sarò un genio, ma non ho mai avuto il compito istuzionale di 
prendere sotto la mia ala nessun giovane. Magari io sono un 
rompicoglioni, non discuto, ma non ho visto nessuno farlo, in nessuna 
realtà che mi è capitato di vedere anche di striscio. Capisco che sono 
più produttivo per l'azienda se *produco*, ma se muoio o mi licenzio le 
mie competenze, la mia esperienza, spariscono con me, e recuperarle 
sarà complesso. Capisco anche che le due o tre star aziendali della 
programmazione non possano essere disturbate (cioè non capisco, ma mi 
adeguo) ma perché io non *debba* dedicare tempo ad insegnare ai giovani 
a crescere non lo capisco.
C'è anche da dire che i programmatori sono una brutta razza, e averci a 
che fare è decisamente complesso.
