2017-01-29 29 views
5

Với đoạn mã sau:tuyên bố thiết lập các chức năng thành viên như một người bạn bằng cách sử dụng mẫu

class A; 

struct B { 
    static void doIt(A* pa); 
}; 

struct C { 
    static void doIt(A* pa); 
}; 

class A { 
    int i = 9; 
    // below works but requires a line per each type 
    friend void B::doIt(A* pa); 
    friend void C::doIt(A* pa); 

    // the below however doesn't work 
    // template<typename T> 
    // friend void T::doIt(A* pa); 
     // (gcc error: member 'void T::doIt(A*)' declared as friend before type 'T' defined) 
     // (clang just ignores the above and the error is on accessing A::i in B and C)  
}; 

void B::doIt(A* pa) { 
    cout << pa->i << endl; 
} 

void C::doIt(A* pa) { 
    cout << pa->i *2 << endl; 
} 

int main() { 
    A a; 
    B::doIt(&a); 
    C::doIt(&a); 
} 

Có thể thay thế nhiều friend tờ khai cho phép tất cả void T::doIt(A* pa) phương pháp truy cập thành viên private của A?

Cố gắng tạo nhanh BC phía trên A không giúp ích gì.

+0

'mẫu bạn trống T :: DoIT (A * pa); 'không phải là một tuyên bố hữu ích. Trình biên dịch cần biết tên của lớp *, * function *, * class-template * hoặc * function-template * làm bạn với 'A'. 'T' không phải là tên mà nó biết và nó không thể tiến hành để làm cho mọi thành viên của' A' có thể truy cập được 'T' – WhiZTiM

+2

Tình bạn không bao giờ là một lựa chọn thiết kế tốt. Nó chỉ là một cách giải quyết trong một số tình huống "tuyệt vọng" ... Hãy coi đây là cơ hội để sửa đổi thiết kế của bạn. –

+1

@ A.S.H: Không đúng. Tình bạn là một cách tuyệt vời để tăng cường đóng gói. –

Trả lời

0

tôi thấy không có cách nào trực tiếp, nhưng một công việc xung quanh có thể được khai báo một lớp học với một số phương pháp tĩnh (thay vì nhiều lớp học với một phương pháp tĩnh) và sau đó tuyên bố lớp này như một người bạn, như:

... 
struct D { 
    static void doItB(A* pa); 
    static void doItC(A* pa); 
}; 

class A { 
... 
    friend struct D; 
... 
}; 

void D::doItB(A* pa) { 
    cout << pa->i << endl; 
} 

... 
    D::doItB(&a); 
    D::doItC(&a); 
... 
+0

Ý tưởng là 'doIt' sẽ được thực hiện trong các lớp khác nhau. Vẫn đang tìm kiếm một số mẹo ... –

2

Không chính xác những gì bạn yêu cầu nhưng ... nếu bạn templatize các cấu trúc B, C, v.v., bạn có thể nhận được một cái gì đó tương tự.

#include <iostream> 

class A; 

template <std::size_t> 
struct X 
{ static void doIt(A* pa); }; 

class A 
{ 
    int i = 9; 

    template <std::size_t I> 
    friend void X<I>::doIt (A* pa); 
}; 

template <> 
void X<0U>::doIt(A* pa) 
{ std::cout << pa->i << std::endl; } 

template <> 
void X<1U>::doIt(A* pa) 
{ std::cout << pa->i * 2 << std::endl; } 

template <> 
void X<2U>::doIt(A* pa) 
{ std::cout << pa->i * 3 << std::endl; } 

using B = X<0U>; 
using C = X<1U>; 
using D = X<2U>; 

int main() { 
    A a; 
    B::doIt(&a); 
    C::doIt(&a); 
    D::doIt(&a); 
} 
+0

Giải pháp hoạt động tốt trên g ++ (6.3.0) nhưng tạo ra một cảnh báo về clang (3.8.0-263969): 'cảnh báo: phụ thuộc tên lồng nhau specifier' X :: 'cho khai báo lớp bạn bè không được hỗ trợ; tắt kiểm soát truy cập đối với người bạn 'A' [-Không được hỗ trợ-bạn bè] void X :: doIt (A * pa); ' Kết quả trong tiếng kêu là' A :: i' có thể được gắn ở bất cứ đâu. Dường như clang đã không thực hiện tính năng này ... –

1

Tôi tin rằng điều gì đó tương tự với những gì bạn mong muốn có thể được thực hiện bằng CRTP và thừa kế riêng tư/được bảo vệ. Mã bên dưới chỉ là minh họa và chắc chắn cần một số công việc, ví dụ: để không liên quan đến mẫu phương pháp hữu:

#include <iostream> 

using namespace std; 

class base { 
protected: 
    int i = 9; 
}; 

template <class F> 
class crtp_base: virtual base { // private inheritance! 
    template <class T> 
    friend void F::doIt(T*); 
}; 

template <class... AllF> 
struct crtp_bases: crtp_base<AllF>... { }; 

struct B { 
    template <class T> 
    static void doIt(T* pa); 
}; 

struct C { 
    template <class T> 
    static void doIt(T* pa); 
}; 

class A: public crtp_bases<B, C> { 
}; 

template <class T> 
void B::doIt(T* pa) { 
    cout << pa->i << endl; 
} 

template <class T> 
void C::doIt(T* pa) { 
    cout << pa->i * 2 << endl; 
} 

int main() { 
    A a; 
    B::doIt(&a); 
    //cout << a.i << endl; // error i is private member of 'base' 
} 

[live demo]

+0

Giải pháp tốt. Nhưng tôi không nghĩ rằng tôi muốn thêm thừa kế cần thiết vào mã. –

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