2009-05-28 15 views
5

Come si modifica il seguente codice per consentire alla funzione modello ask_runUI() di utilizzare s_EOF senza rendere pubblico lo s_EOF?Come consentire alla funzione modello di avere accesso amico (-like)?

#include <string> 
#include <iostream> 
#include <sstream> 
#include <vector> 
class AskBase { 
protected: 
    std::string m_prompt; 
    std::string m_answer; 
    virtual bool validate(std::string a_response) = 0; 
public: 
    AskBase(std::string a_prompt):m_prompt(a_prompt){} 
    std::string prompt(){return m_prompt;} 
    std::string answer(){return m_answer;} 
    static int const s_EOF = -99; 
    static int const s_BACKUP = -1; 
    static int const s_OK = 1; 
    int ask_user(); 
}; 
template<typename T> class Ask : public AskBase{ 
public: 
    Ask(std::string a_prompt):AskBase(a_prompt){} 
    bool validate(std::string a_response); 
}; 
template<> bool Ask<std::string>::validate(std::string a_response){return true;} 
template<> bool Ask<int>::validate(std::string a_response){int intAnswer; 
    return (std::stringstream(a_response) >> intAnswer);} 
int AskBase::ask_user(){ 
    for(;;){ 
     std::cout << "Enter " << m_prompt; 
     std::string response; 
     getline(std::cin, response); 
     if (std::cin.eof()) 
      return s_EOF; 
     else if (response == "^") 
      return s_BACKUP; 
     else if (validate(response)){ 
      m_answer = response; 
      return s_OK; 
     } 
    } 
    return s_EOF; 
} 
template<typename T> int ask_runUI(T& a_ui){ 
    int status = AskBase::s_OK; 
    for (typename T::iterator ii=a_ui.begin(); 
      status!=AskBase::s_EOF && ii!=a_ui.end(); 
      ii+=((status==AskBase::s_BACKUP)?((ii==a_ui.begin())?0:-1):1) 
     status = (*ii)->ask_user(); 
    return (status == AskBase::s_OK); 
} 
int main(){ 
    std::vector<AskBase*> ui; 
    ui.push_back(new Ask<std::string>("your name: ")); 
    ui.push_back(new Ask<int>("your age: ")); 
    if (ask_runUI(ui)) 
     for (std::vector<AskBase*>::iterator ii=ui.begin(); ii!=ui.end(); ++ii) 
      std::cout << (*ii)->prompt() << (*ii)->answer() << std::endl; 
    else 
     std::cout << "\nEOF\n"; 
} 
+0

La prossima volta, utilizzare 'int ask_runUI()' (il '' contrassegna come codice). –

+0

Se si restituisce il numero, perché dovrebbe essere privato? –

+0

Ho espanso l'esempio per mostrare che solo AskBase :: ask_user() restituisce s_EOF che viene utilizzato solo da ask_runUI(). –

risposta

22

Se si desidera una funzione di modello per essere un amico, è necessario dirlo nella dichiarazione della classe. Modificare la riga che dichiara la funzione amico a questo:

template <typename T> 
friend int ask_runUI(T& a_ui); 

Ora, se la classe è di per sé un modello, le cose si fanno molto più complicato. Gli amici del modello non sono banali da fare correttamente. Per questo, ti rimanderò a ciò che dice C++ FAQ Lite sull'argomento.

-2

Il più semplice è probabilmente quello di sostituire i static int const membri con l'enumerazione e si scherza con friend s:


class AskBase { 
public: 
    enum { Eof = -99, Null = 0, Ok = 1, Backup = -1 }; 
    ... 
}; 
+0

-1. Non vedo come questo cambi qualcosa - il tuo enum, che hai dichiarato pubblico, è in ogni modo materiale equivalente a rendere pubblici i membri const const. Se c'è qualche distinzione che mi è sfuggita, per favore dì e riconsidererò. –

+0

La distinzione è che il compilatore non deve allocare spazio per le variabili membro statiche. Il vantaggio è che è SEMPLICE. –

+0

Beh, ho fatto qualche ricerca ed è più strano di quanto pensassi. Per esempio, se dichiari e inizializzi semplicemente i membri stat const const all'interno della definizione di classe * senza * definendoli a livello di spazio dei nomi (cioè senza scrivere "statict const int AskBase :: s_Eof;" ecc. A livello di spazio dei nomi) allora non ci sarà spazio mai assegnato MA, il compilatore ti consentirà solo di riferirti a s_Eof come valore di rvalue (ad es. Il binding a un riferimento non const fallirà al momento del collegamento !!) Vedi qui: http://stackoverflow.com/questions/272900/c-undefined -rapporto-a-statico-membro della classe, in particolare la risposta di Richard Corden. –

2

Questo ha funzionato per me!

class AskBase { 
public: 
    AskBase(){} 
    template<typename T> 
    friend int ask_runUI(T& a_ui); 
private: 
    static int const s_EOF = -99; 
    static int const s_BACKUP = -1; 
    static int const s_NULL = 0; 
    static int const s_OK = 1; 
}; 
//int ask_runUI() 
template<typename T> 
int ask_runUI(T& a_ui) 
{ 
    return AskBase::s_NULL; 
} 
+1

Questo è il classico anti-pattern per l'amicizia con un metodo di template. Fondamentalmente è lo stesso che rendere pubblici tutti i membri poiché chiunque può scrivere la propria versione di ask_runUI() –

+3

Possono, ma lo faranno per caso, senza rendersi conto di quello che stanno facendo? Soprattutto se ask_UI si trova nello stesso spazio dei nomi della classe, se vanno a curiosare nell'interfaccia di una classe, sicuramente sanno che stanno rompendo l'incapsulamento? –

Problemi correlati