PDA

View Full Version : [C++] Urgente: Magheggi con funzioni friend


Ikon O'Cluster
03-09-2009, 19:52
Volevo sapere se si può e se no come si può fare qualcosa del genere:


class A;

class B {
void funB(A a) {a.funA();} // VORREI CHE SIA CORRETTO (ORA E' SEGNALATO COME ERRORE PERCHE' funA NON E' DEFINITA)
void funC(A a) {a.funA();} // DEVE ESSERE RILEVATO COME ERRORE
}

class A {
friend void B::funB(A a);

protected:
void funA() {/*...*/};
}


So che si può dichiarare friend la classe B, ma io voglio che solo funB possa chiamare funA, mentre funC non deve poterlo fare.

tomminno
03-09-2009, 23:32
Direi che quello che vuoi fare non è fattibile e oltretutto pone di fronte ad errori di progettazione.
Perchè mai solo un metodo di B dovrebbe accedere ad A?
Se spieghi meglio il contesto forse è possibile trovare una soluzione differente.

funB e funC fanno parte dello stesso contesto ovvero class B, e se funC richiamasse funB più o meno direttamente dovrebbe segnalarti errore?
Credo che la richiesta non sia ragionevole, anche perchè allora potresti pensare che funC richiami un metodo di class C dichiarata come friend di class B che a sua volta richiama funB, risultato atteso?

Ikon O'Cluster
04-09-2009, 10:57
Perchè volevo che la classe B accedesse ad A soltanto con una funzione membro e non con tutte le funzioni membro. In realtà la mia situazione è questa.


class A;

class B {
void funC(A a) {a.funB(a);} // PUO' ACCEDERE AD A SOLO SE CHIAMA funB

protected:
void funB(A a) {a.funA();} // VORREI CHE SIA CORRETTO (ORA E' SEGNALATO COME ERRORE PERCHE' funA NON E' DEFINITA)
}

class A {
friend void B::funB(A a);

protected:
void funA() {/*...*/};
}


Io voglio che la classe B abbia una funzione membro funB incaricata di accedere ad A (perchè unica friend), mentre il resto di B deve per forza far riferimento a funB.

Perchè funA è incaricata di modificare A. E funB è l'unica incaricata di accedere a B. Vorrei che funB-funA siano una specie di "ponte" tra A e B...

Tommo
04-09-2009, 12:14
Secondo me, devi riorganizzare il codice e lasciar stare friend...

spesso quando c'è la stretta necessità di usare friend c'è un errore "di dominio": cioè, se B dipende così strettamente da alcune funzioni di A tanto da dover essere dichiarata friend, probabilmente quelle funzioni non stanno bene dove stanno.

Potresti incapsularle in una classe C che le rende pubbliche, potresti spostarle in B, ecc.

Magari se spieghi meglio il contesto possiamo aiutarti in questo...:D

Ikon O'Cluster
04-09-2009, 17:27
Il codice sottomano non posso pubblicarlo perchè è secretato, ma il concetto è questo:

1) Esistono dei "semi-lavorati":

class SemiLavorato {
protected:
Tipo1 campo1;
TipoN campoN;
public:
void set1(Tipo1 t) {campo1 = t;}
void setN(TipoN t) {campoN = t;}

Tipo1 get1() {return campo1;}
TipoN getN() {returncampoN;}
}

2) Esiste una classe che esegue la lavorazione:

class Lavorazione {
protected:
Prodotto output;
void lavorazione(Semilavorato sl) {output.tick(); output.trasformazione(sl);}
public:
void acquisisci(SemiLavorato sl) {qualcosa(); lavorazione(sl);}
Prodotto estrai() {return p;}
}

3) I prodotti sono del tipo:

class Product {
protected:
unsigned int time1;
unsigned int timeN;
TipoFinito1 campo1;
TipoFinitoN campoN;
void tick() {time1++; timeN++;} // Deve poter essere eseguita solo da Lavorazione::lavorazione
public:
void trasformazione(SemiLavorato sl) {/* Lavora solo alcuni TipiFiniti ma non si sa quali a priori, quindi per quelli lavorati imposta timeX=0 per gli altri li lascia inalterati. */}
}



Quello che voglio è che solo Lavorazione possa effettuare lavorazioni su Prodotto. Una volta finita la lavorazione chi ottiene prodotto con estrai() non può più lavorarci sopra. Ma anche chi maneggia Lavorazione non deve poter arbitrariamente operare su Prodotto. In particolare non deve toccare i timeX e quindi invocare la tick(). Perlomeno deve poterci operare solo se effettua una acquisisci() o altre funzioni che richiamano trasformazione().

Tommo
04-09-2009, 18:34
Boh, mi sembra confuso :asd:

Cmq una cosa che potresti fare molto semplice è mettere dentro a prodotto un bel bool "finalized" e un bel metodo void finalize();

così finalize è pubblico, ma quando viene chiamato "blocca" le modifiche a Prodotto.

Altrimenti puoi sempre usare la convenzione _metodo() affiancata da un bel commento che invita a non usarlo sul metodo che vuoi rendere interno...
ricorda che protected è pur sempre una convenzione, non è strettamente *necessario*.

Nella quasi totalità delle librerie OOP è facile trovare metodi pubblici cosiddetti "internal" che servono proprio a questo scopo...

tomminno
04-09-2009, 20:03
Quello che voglio è che solo Lavorazione possa effettuare lavorazioni su Prodotto.


E se lavorazione la definisci come un "ProductProcessing" che deriva da Product tramite ereditarietà privata?
A questo punto hai accesso a tutti i metodi protected.
Dopotutto è un altro modo per rappresentare la composizione di oggetti, come l'avevi fatta te, solo che il legame diventa più stretto e sei sicuro che non si possa casta un ProductProcessing a Product


Una volta finita la lavorazione chi ottiene prodotto con estrai() non può più lavorarci sopra.


Come sopra, rispetteresti il requisito, in quanto un oggetto Product non è modificabile se non da ProductProcessing.


Ma anche chi maneggia Lavorazione non deve poter arbitrariamente operare su Prodotto. In particolare non deve toccare i timeX e quindi invocare la tick(). Perlomeno deve poterci operare solo se effettua una acquisisci() o altre funzioni che richiamano trasformazione().

Idem come sopra, non puoi lavorare su un oggetto Product, ma lo fai solo tramite i metodi pubblici di ProductProcessing.

Ikon O'Cluster
04-09-2009, 20:07
Uhm... ci studio un po', cmq mi sembra pacifico il ragionamento di tommino. In ogni caso io ora ho definito friend l'intera classe e sostanzialmente è altrettanto pulito in termini di leggibilità/comprensione (anche dati i commenti).

Grazie per le risposte.