2012-03-17 12 views
5

voglio un tipo Un che produrrà il suo dato di nascosto a un oggetto di tipo T ma nascondere il dato da tutti gli altri. Il mio compilatore C++ sembra essere GCC 4.4, ma non dovrebbe essere importante. Perché non funzionerà?Come nascondere un dato da tutti, ma di classe T

#include <iostream> 

template <class T> class A { 
    private: 
    int n1; 
    public: 
    friend class T; 
    A(const int n0 = 0) : n1(n0) {} 
}; 

class B { 
    public: 
    int f(const A<B> a) const { return a.n1; } 
    B() {} 
}; 

int main() { 
    const A<B> a(5); 
    const B b; 
    const int m = b.f(a); 
    std::cout << m << "\n"; 
    return 0; 
} 

Per inciso, questo funziona bene, solo che non riesce a nascondere il dato:

#include <iostream> 

template <class T> class A { 
    private: 
    int n1; 
    public: 
    int n() const { return n1; } 
    A(const int n0 = 0) : n1(n0) {} 
}; 

class B { 
    public: 
    int f(const A<B> a) const { return a.n(); } 
    B() {} 
}; 

int main() { 
    const A<B> a(5); 
    const B b; 
    const int m = b.f(a); 
    std::cout << m << "\n"; 
    return 0; 
} 

non C++ in realtà non consente una classe amico da specificare al momento della compilazione come un parametro di modello? Perchè no? In caso contrario, quale tecnica alternativa dovrei usare per nascondere il dato? (Si preferirebbe una tecnica in fase di compilazione, se possibile.)

Qual è il mio malinteso qui, per favore?

(Vedo alcune risposte alle domande correlate here e here, ma non rispondono alla mia domanda specifica o non riesco a capire che lo fanno. In ogni caso, forse sto usando la tecnica sbagliata del tutto. rimangono interessati perché la classe amico T non riesce, quello che voglio sapere è come nascondere il dato, sia con un amico o con altri mezzi.)

Grazie.

risposta

1

Non conosco lo standard dietro il tuo errore (fai riferimento alla risposta di Xeo), ma ho trovato una soluzione alternativa per C++ 03. Invece di fare T un amico, fare una delle funzioni membro T s' un amico:

#include <iostream> 

template <class T> class A { 
    private: 
    int n1; 
    public: 
    friend int T::getN1(const A& a) const; 
    A(const int n0 = 0) : n1(n0) {} 
}; 

class B { 
    public: 
    int f(const A<B> a) const { return getN1(a); } 
    B() {} 
    private: 
    int getN1(const A<B>& a) const {return a.n1;} 
}; 

class C { 
    public: 
    int f(const A<B> a) const { return getN1(a); } 
    C() {} 
    private: 
    // Error, n1 is a private member of A<B> 
    int getN1(const A<B>& a) const {return a.n1;} 
}; 

int main() { 
    const A<B> a(5); 
    const B b; 
    const int m = b.f(a); 
    std::cout << m << "\n"; 
    return 0; 
} 

In alternativa, si può fare una nidificato classe/struttura di T essere un amico di A. Questo può essere più conveniente se ci sono diversi membri privati ​​di A a cui T ha accesso.

#include <iostream> 

template <class T> class A { 
    private: 
    int n1; 
    public: 
    friend class T::AccessToA; 
    A(const int n0 = 0) : n1(n0) {} 
}; 

class B { 
    public: 
    int f(const A<B> a) const { return AccessToA::getN1(a); } 
    B() {}; 
    private: 
    friend class A<B>; 
    struct AccessToA 
    { 
     static int getN1(const A<B>& a) {return a.n1;} 
    }; 
}; 

class C { 
    public: 
    int f(const A<B> a) const { return AccessToA::getN1(a); } 
    C() {}; 

    private: 
    friend class A<C>; 
    struct AccessToA 
    { 
     // Error, n1 is a private member of A<B> 
     static int getN1(const A<B>& a) {return a.n1;} 
    }; 
}; 

int main() { 
    const A<B> a(5); 
    const B b; 
    const int m = b.f(a); 
    std::cout << m << "\n"; 
    return 0; 
} 
+0

Buon consiglio. A meno che non riesca a trovare qualcosa di meglio, dovrei seguire il consiglio. Grazie. – thb

+0

Controlla anche l'idioma passkey suggerito da Xeo, così come l'idioma del procuratore-cliente. È passato un po 'di tempo da quando ho letto di questi, quindi la mia soluzione potrebbe benissimo essere una variante di quegli idiomi. –

4

Il compilatore è semplicemente troppo vecchio. C++ 11 ti consente di dichiarare i parametri del modello come amici.

§11.3 [class.friend] p3

Una dichiarazione amico che non dichiarare una funzione devono avere una delle seguenti forme:

  • friendelaborated-type-specifier;
  • friendsimple-type-specifier;
  • friendtypename-specifier;

Se il tipo specificatore in una dichiarazione friend designa un (possibilmente cv-qualificato) tipo di classe, tale classe viene dichiarata come friend; in caso contrario, la dichiarazione dell'amico viene ignorata.

E contiene anche un esempio di un parametro di modello come un amico:

class C; 
// [...] 
template <typename T> class R { 
    friend T; 
}; 

R<C> rc; // class C is a friend of R<C> 
R<int> ri; // OK: "friend int;" is ignored 

C++ 03 ha purtroppo alcun modo per fare questo, però si può semplicemente amico una sola funzione libera e lasciare che agisce come codice "colla" che prende i dati da una classe e li passa all'altro. Un altro modo potrebbe essere il passkey pattern.

+0

Capisco. Grazie. Grazie anche per l'illuminante passkey link. – thb

Problemi correlati