2011-12-23 27 views
8

Vui lòng xem my first attempt at answering this . Tôi đã bỏ quên kể toàn bộ câu chuyện trước đây trong một nỗ lực để đơn giản hóa mọi thứ. Hóa ra ví dụ của tôi hoạt động! Lấy làm tiếc.Làm thế nào để tôi làm cho một người bạn chính của lớp học của tôi từ trong thư viện?

Toàn bộ câu chuyện là đây là thư viện chứa một lớp trong một tệp và tệp chính trong một tệp khác, tất cả được liên kết trong thư viện của tôi. Thư viện đang cung cấp cơ sở cho một Khung Quy trình, đó là lý do tại sao thư viện chính nằm trong thư viện chứ không phải là quy trình.

Dưới đây là phiên bản rút gọn của những gì tôi có.

pf.hpp

using namespace std; 

namespace MyNamespace 
{ 
    class ProcessManager 
    { 
    public: 
    friend int main(int argc, char** argv); 
    private: 
    void test(); 
    }; 
}; 

pf.cpp

#include "pf.h" 

namespace MyNamespace 
{ 
    ProcessManager::test() 
    { 
    cout << "My friend has accessed my member" << endl; 
    } 
}; 

pfmain.cpp

#include "pf.hpp" 

int main(int argc, char** argv) 
{ 
    ProcessManager pm; 

    pm.test(); 
} 

Lưu ý rằng điều này không thành trong việc lập thư viện

Những gì tôi đã thử là:

  • Moving người bạn khắp nơi
  • Làm tài liệu tham khảo bạn bè để sử dụng chính phạm vi toàn cầu (ví dụ :: chính)
  • Làm người bạn và chính tờ khai sử dụng phạm vi toàn cầu

tôi thiếu gì?

Cảm ơn!

+1

Đây là một chút ngoài chủ đề, nhưng rất nhiều người sẽ nói rằng từ khóa 'friend' không bao giờ là một giải pháp tốt. – asveikau

+0

Nó không lý tưởng tôi đồng ý, nhưng đôi khi bạn không có lựa chọn tốt khác thay thế – Jaime

+0

Có thể muốn xem xét kết bạn với các biến thể khác của 'main()'. Không chắc chắn nếu họ đang trên Facebook mặc dù. –

Trả lời

9

Chỉ cần khai báo chính ngoài MyNamespace và xác định không gian tên toàn cầu :: trong bản Tuyên Bố bạn

//in header file of ProcessManager 
//your pf.h 

int main(int argc, char** argv); 

namespace MyNamespace 
{ 
    class ProcessManager 
    { 
    public: 
    friend int ::main(int argc, char** argv); 
    private: 
    void test(); 
    }; 
}; 
+0

Tôi không thấy lý do tại sao trình biên dịch sẽ không nhìn thấy chính từ pfmain.cpp trong trường hợp của tôi, nhưng điều này hoạt động. Cảm ơn! – Jaime

+0

Các lần thử trước sẽ hiển thị lỗi "lỗi: 'int main (int, char **)' nên đã được khai báo bên trong '::'" cần phải nói đủ, nhưng tôi sẽ không bao giờ mong đợi trình biên dịch không kiểm tra các tệp .o khác cho biểu tượng xem xét cách đặt tiêu đề .. – Jaime

+0

@Jaime trong chính C++() phải được khai báo trong không gian tên chung. Tuy nhiên, tên không được bảo lưu và có thể được sử dụng cho các chức năng của thành viên và trong các không gian tên trong số các vị trí khác. –

0

Một câu trả lời phổ biến có thể là để cung cấp một "ứng dụng" lớp singleton, như ví dụ QApplication trong Qt, một giảm main của bạn để một cái gì đó giống như

int main (int argc, char** argv) { 
    YourApplication app (argc, argv); 
    return app.execute(); 
} 

Sau đó, bạn giảm mối quan tâm của bạn để friendness class YourApplication vs các lớp khác của bạn, và bạn biết làm thế nào để làm điều đó.

+0

Lớp thực sự đã là một singleton, tôi chỉ không cho thấy phần đó. Có một singleton không giải quyết vấn đề mặc dù .. – Jaime

0

Tôi không nghĩ bạn thực sự muốn làm những gì bạn đang làm. Điều này thực sự có vẻ như một hack và một vấn đề thiết kế. Nếu bạn thực sự muốn để lộ các lớp bên trong của lớp học của bạn trong một số trường hợp chuyên ngành, bạn có thể làm cho một lớp accessor mà cũng được xác định bên trong thư viện của bạn.

Something như thế này có thể làm việc (có thể cần tờ khai chuyển tiếp thích hợp, vv - đây chỉ là một điểm khởi đầu):

class ProcessManagerAccessor 
{ 
public: 
    ProcessManagerAccessor(ProcessManager & pm) : pm_(pm) { } 

    // add public methods to expose internals 
    void test() { pm_.test(); } 

private: 
    ProcessManager & pm_; 
}; 

class ProcessManager 
{ 
public: 
    friend class ProcessManagerAccessor; 

    // ... 
}; 

// ... 

ProcessManager pm; 
ProcessManagerAccessor pma(pm); 
pma.test(); 
+0

"Nói chung, bạn không muốn để phá vỡ bất kỳ đóng gói vì lợi ích của thử nghiệm (hoặc như mẹ được sử dụng để nói," không tiếp xúc với tư nhân của bạn! "). Nếu có chức năng quan trọng ẩn đằng sau quyền truy cập riêng tư hoặc được bảo vệ, đó có thể là dấu hiệu cảnh báo rằng có một lớp khác trong đó đang vật lộn để thoát ra ngoài. " – bobbymcr

+0

Tôi không thấy điều này như bất kỳ sự khác biệt nào so với việc cấp quyền truy cập chính. Vấn đề là lớp của tôi là một Singleton, được tạo ra mà không có các tham số, nhưng tôi cần thiết lập một số trạng thái trong chính trước khi tôi kiểm soát lớp dẫn xuất của ProcessManager. Tôi không muốn các phương thức này có thể truy cập được bởi lớp dẫn xuất. – Jaime

+0

phương pháp "thử nghiệm" chỉ là một ví dụ ... nó không thực sự được sử dụng để thử nghiệm – Jaime

2

@parapura cung cấp một giải pháp, nhưng không giải thích lý do tại sao bạn trước tiên phải khai báo main trong phạm vi toàn cầu.

§7.3.1.2 [namespace.memdef] p3

[...] If a friend declaration in a nonlocal class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. [...]

Vì vậy, với ý nghĩ đó, mã của bạn sẽ trông hơi như thế này:

namespace MyNamespace 
{ // MyNamespace is the innermost enclosing namespace 
    // 'main' from the friend declaration is treated 
    // as if it was a member of 'MyNamespace' 
    int main(int argc, char** argv); 

    class ProcessManager 
    { 
    public: 
    friend int main(int argc, char** argv); 
    private: 
    void test(); 
    }; 
}; 

Bây giờ nó phải rõ ràng lý do tại sao toàn cầu main chức năng không phải là bạn của bạn.

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