2009-05-28 18 views
5

s_EOFを公開せずに、テンプレート関数ask_runUI()s_EOFを使用できるようにするには、次のコードを変更するにはどうすればよいですか?テンプレート機能に友達(のような)アクセスを許可するにはどうすればいいですか?

#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

次回は 'int ask_runUI()'( ''コードとしてマークする)を使用してください。 –

+0

番号を返信している場合は、なぜプライベートにする必要がありますか? –

+0

この例を拡張して、AskBase :: ask_user()のみがask_runUI()によってのみ使用されるs_EOFを返すことを示しました。 –

答えて

22

テンプレート関数を友人にしたい場合は、クラス宣言でsoと言う必要があります。これにフレンド関数を宣言して行変更:あなたのクラスはテンプレート自体であれば今

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

を、物事は多くの複雑になります。テンプレートの友人は正しく行うのが簡単ではありません。そのために、C++ FAQ Liteがその件について述べていることを紹介します。

-2

最も簡単なのはfriend sの列挙と台無しにしないでstatic int constメンバーを置き換えるために、おそらくです:


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

-1。私はこれがどのように変化するのか分かりません。あなたが宣言したあなたのenumは静的const intメンバをpublicにすることと同じように、あらゆる重要な点で同じです。もし私が見逃してしまった区別があれば、私が再考してください。 –

+0

コンパイラは静的メンバー変数のための領域を割り当てる必要がないという違いがあります。利点は簡単だということです。 –

+0

さて、私はいくつかの研究を行い、それは私が思ったよりも怪しいです。静的const intメンバーを名前空間レベルで定義せずに(つまり、名前空間レベルで "statict const int AskBase :: s_Eof;"などを書き込まずに)クラス定義*内に宣言して初期化するだけの場合、スペースはありませんこれまで割り当てられたことはない。しかし、コンパイラは、s_Eofをrvalueとして参照できるようにします(例えば、非const参照へのバインドはリンク時には失敗します!!)。ここを参照してください:http://stackoverflow.com/questions/272900/c-undefined -reference-to-static-class-member、特にRichard Cordenの答え。 –

2

これは私のために働きました!

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

これは、テンプレートメソッドをfriendingするための古典的なアンチパターンです。誰もが自分のバージョンのask_runUI()を書くことができるように、すべてのメンバーを公開させるのと基本的に同じです –

+3

彼らは何をしているのかを意識することなく、偶然にそうすることができます。特にask_UIがクラスと同じ名前空間にある場合、クラスのインターフェイスの内部を突き抜けてしまうと、カプセル化が破られていることは間違いありません。 –

関連する問題