2009-05-28 31 views
5

Làm cách nào để sửa đổi mã sau để cho phép chức năng mẫu ask_runUI() sử dụng s_EOF mà không thực hiện công khai s_EOF?Cách cho phép chức năng mẫu có quyền truy cập bạn bè (giống như)?

#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

Lần tiếp theo, vui lòng sử dụng 'int ask_runUI()' ('' đánh dấu là mã). –

+0

Nếu bạn trả lại số, tại sao nó phải là riêng tư? –

+0

Tôi mở rộng ví dụ để cho thấy rằng chỉ AskBase :: ask_user() trả về s_EOF mà chỉ được sử dụng bởi ask_runUI(). –

Trả lời

22

Nếu bạn muốn mẫu có chức năng làm bạn, bạn phải nói như vậy trong tuyên bố lớp học. Thay đổi dòng tuyên bố chức năng bạn bè cho điều này:

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

Bây giờ, nếu lớp của bạn là một mẫu, mọi thứ phức tạp hơn nhiều. Bạn bè mẫu không phải là tầm thường để làm đúng. Để làm được điều đó, tôi sẽ giới thiệu cho bạn những gì C++ FAQ Lite nói về chủ đề này.

-2

Cách đơn giản nhất có lẽ là để thay thế static int const thành viên với liệt kê và không gây rối với friend s:


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

-1. Tôi không thấy làm thế nào điều này thay đổi bất cứ điều gì - enum của bạn, mà bạn đã tuyên bố công khai, là trong mọi cách vật chất tương đương với chỉ làm cho các thành viên int const tĩnh công cộng. Nếu có một số khác biệt mà tôi đã bỏ lỡ, hãy nói và tôi sẽ xem xét lại. –

+0

Sự khác biệt là trình biên dịch không phải phân bổ không gian cho các biến thành viên tĩnh. Ưu điểm là nó là SIMPLE. –

+0

Vâng, tôi đã làm một số nghiên cứu và nó là weirder hơn tôi nghĩ. Đối với một, nếu bạn chỉ cần khai báo và khởi tạo các thành viên int const tĩnh bên trong định nghĩa lớp * mà không * định nghĩa chúng ở mức không gian tên (nghĩa là không viết "statict const int AskBase :: s_Eof;" .vv ở mức không gian tên) thì sẽ không có khoảng trống nào bao giờ được phân bổ. NHƯNG, trình biên dịch sẽ chỉ cho phép bạn tham khảo s_Eof như là một rvalue (ví dụ như ràng buộc với một non-const ref sẽ thất bại tại thời gian liên kết !!) Xem tại đây: http://stackoverflow.com/questions/272900/c-undefined - thành viên-lớp-tĩnh-tĩnh, đặc biệt là câu trả lời của Richard Corden. –

2

này đã làm việc cho tôi!

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

Đó là kiểu chống cổ điển để kết bạn với một phương thức mẫu. Về cơ bản, cũng giống như việc đưa tất cả thành viên ra công khai vì bây giờ ai cũng có thể viết phiên bản ask_runUI của riêng họ() –

+3

Họ có thể, nhưng họ sẽ vô tình làm như vậy mà không nhận ra đó là những gì họ đang làm? Đặc biệt là nếu ask_UI nằm trong cùng một không gian tên như lớp, nếu chúng đi xung quanh bên trong giao diện của lớp thì chắc chắn chúng biết chúng đang bẻ khóa đóng gói? –

Các vấn đề liên quan