2012-06-15 29 views
5

Giả sử chúng ta có hai lớp:Làm cách nào để lớp học chỉ có thể truy cập một số thành viên riêng tư của một lớp học khác?

class Base 
{ 
private: 
    int x; 
public: 
    void f(); 
}; 

class Foo 
{ 
    // some variables and methods 
}; 

Bây giờ tất cả mọi người có thể gọi Base::f(), nhưng tôi muốn chỉ Foo để có thể làm như vậy.

Để đạt được hiệu ứng này, chúng ta có thể làm cho Base::f() tin và tuyên bố Foo làm bạn bè:

class Base 
{ 
private: 
    int x; 
    void f(); 
    friend Foo; 
}; 

Vấn đề với phương pháp này là Foo có quyền truy cập vào cả hai Base::f()Base::x (và thậm chí để bất kỳ thành viên riêng tư nào khác của Base). Nhưng tôi muốn Foo chỉ có quyền truy cập vào Base::f().

Có cách nào cho một lớp học (hoặc một hàm) chỉ cấp quyền truy cập cho một số thành viên riêng tư của một lớp khác không? Hoặc có lẽ ai cũng có thể đề xuất một cách tiếp cận tốt hơn cho vấn đề của tôi?

EDIT:

Tôi sẽ cố gắng để xác định hạn chế quyền truy cập tôi cần. Thứ nhất, Base là một giao diện trong một thư viện (đó là một lớp trừu tượng, trên thực tế). Người dùng chỉ sử dụng các lớp bắt nguồn từ Base. Base::f() chỉ được gọi là Foo là một lớp khác trong thư viện. Ẩn Base::f() từ người dùng là quan trọng, bởi vì chỉ Foo biết khi nào nên gọi nó. Đồng thời, Foo không được làm hỏng các thành viên khác của Base.

+0

Bạn có thể bảo vệ 'f()' và sử dụng quyền thừa kế được bảo vệ mà tôi nghĩ. – chris

+0

Nhưng 'Foo' không xuất phát từ' Base'. – miloszmaki

+0

Đó chỉ là một ý nghĩ. Bạn sẽ phải lấy nó. Sau khi nhìn thấy câu trả lời 'BaseData', tôi sẽ đi với điều đó. – chris

Trả lời

6

Rất khó, nhưng điều này sẽ cho phép truy cập hạt rất tốt.

class Base 
{ 
private: 
    int x; 
    void f(); 
    friend class Base_f_Accessor; 
}; 

class Base_f_Accessor 
{ 
private: 
    static void f(Base & b) { b.f(); } 
    friend class Foo; 
} 

class Foo 
{ 
    // some variables and methods 
}; 
+0

Tôi thích cách tiếp cận này, vì nó cho phép ẩn các chi tiết thực hiện của 'Base_f_Accessor' trong một tệp .cpp. Bằng cách này, 'Foo' cũng có thể được định nghĩa trong tệp .cpp và không được tiếp xúc với người dùng. – miloszmaki

4

Bạn có thể tạo một lớp có chứa các dữ liệu cho Base như thế này:

class BaseData { 
protected: 
    int x; 
}; 

class Base : public BaseData { 
    friend class Foo; 
    void f(); 
}; 

Bây giờ, Foo có thể truy cập f như một phương pháp Base như bạn muốn, nhưng không x. Tình bạn không phải là giao hoán. Bằng cách sử dụng protected, x hiển thị riêng tư cho tất cả mọi người trừ những người có nguồn gốc trực tiếp từ BaseData.

Cách tiếp cận tốt hơn có thể là sử dụng đa thừa kế để xác định Base và chỉ cung cấp quyền truy cập Foo vào các lớp bạn muốn mà từ đó Base xuất phát.

class With_f { 
    friend class Foo; 
protected: 
    virtual void f() = 0; 
}; 

class With_g { 
protected: 
    virtual void g() = 0; 
}; 

class Base : public With_f, public With_g { 
    int x; 
    void f() {} 
    void g() {} 
}; 

Ở đây, Foo sẽ phải có một con trỏ With_f-Base, nhưng sau đó nó có thể truy cập vào các phương pháp f. Foo không thể truy cập g.

+0

Điều gì sẽ xảy ra nếu bạn tạo 'Base' là bạn của' BaseData'? Bạn bè của 'Base' có thể truy cập nó không? Tôi nghĩ điều đó sẽ tốt hơn là thừa kế nếu nó hoạt động như thế. – chris

+0

@chris: Một người bạn của một người bạn không phải là bạn trong C++. – jxh

+0

Sau đó, có lẽ sẽ làm tốt hơn việc giới thiệu thừa kế. – chris

2

Không có cách nào dễ dàng, không hackish để đạt được điều đó. C++ chỉ đơn giản là không có quyền kiểm soát truy cập như vậy. Bạn có thể chơi với một số thừa kế, nhưng tăng độ phức tạp vượt quá bất kỳ lợi thế giới hạn truy cập này có thể có. Ngoài ra, cách tiếp cận này không mở rộng quy mô - bạn có thể cấp quyền gia tăng chỉ cho một lớp bạn bè.

0

Có thể hơi cồng kềnh, nhưng bạn có thể tạo lớp lồng nhau trong đó lớp lồng nhau là bạn, sau đó bạn có thể thêm bạn bè cho mỗi lớp lồng nhau. Điều này cung cấp một số mức độ chi tiết:

#include <iostream> 

class Nesting 
{ 
    friend class Foo; 
    class Nested1 
    { 
    friend class Nesting; 
    public: 
    Nested1() : i(3) { } 
    private: 
    int i; 
    } n1; 
    class Nested2 
    { 
    friend class Nesting; 
    friend class Foo; 
    public: 
    Nested2() : j(5) { } 
    private: 
    int j; 
    } n2; 
    int f() { return n1.i; } 
}; 

class Foo 
{ 
public: 
    Foo(Nesting& n1) : n(n1) { } 
    int getJ() { return n.n2.j + n.f(); } 
private: 
    Nesting& n; 
}; 

int main() 
{ 
    Nesting n; 
    Foo foo(n); 
    std::cout << foo.getJ() << "\n"; 
} 
Các vấn đề liên quan