2012-06-15 37 views
5

假设我们有两大类:如何让一个班级只能访问其他班级的某些私人成员?

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

class Foo 
{ 
    // some variables and methods 
}; 

现在每个人都可以打电话Base::f(),但我只想要Foo能够这样做。

为了达到这个效果,我们可以使Base::f()私人和声明Foo为好友:

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

这种方法的问题是,Foo有同时访问Base::f()Base::x(甚至Base的任何其他私人成员)。但我想Foo只能访问Base::f()

有没有办法让一个类(或一个函数)只允许访问另一个类的某些私有成员?或者,也许任何人都可以提出更好的方法来解决我的问题?

编辑:

我会尝试以指定的访问限制,我需要。首先,Base是库中的一个接口(实际上它是一个抽象类)。用户只使用派生自Base的类。 Base::f()仅被Foo调用,这是库中的另一个类。从用户隐藏Base::f()很重要,因为只有Foo知道何时调用它。同时,Foo不应该混淆Base的其他成员。

+0

您可以使'f()'受保护,并使用受保护的继承我认为。 – chris

+0

但'Foo'不是从'Base'派生的。 – miloszmaki

+0

这只是一个想法。你必须得到它。看到“BaseData”答案后,我会继续这样做。 – chris

回答

6

很hacky,但是这会允许非常细微的访问。

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

我喜欢这种方法,因为它允许在.cpp文件中隐藏'Base_f_Accessor'的实现细节。这样,'Foo'也可以在.cpp文件中定义,而不会暴露给用户。 – miloszmaki

4

您可以创建一个包含数据Base这样的另一个类:

class BaseData { 
protected: 
    int x; 
}; 

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

现在,Foo可以访问fBase的方法就像你想要的,但不是x。友谊是不可交换的。通过使用protectedx对除了直接从BaseData直接派生的所有人显示为私人。

一个更好的办法可能是使用多重继承来定义Base,并提供Foo只能访问您想从中导出Base这些类。

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() {} 
}; 

这里,Foo就必须有一个With_f指针Base,但随后它可以访问f方法。 Foo无法访问g

+0

如果您将'Base'作为'BaseData'的朋友,会发生什么? “Base”的朋友是否也可以访问它?如果它像那样工作,我认为这会比继承更好。 – chris

+0

@chris:朋友的朋友不是C++中的朋友。 – jxh

+0

然后,这可能会比介绍继承更好。 – chris

2

有没有简单的,非hackish的方式来实现这一目标。 C++根本没有这样的访问控制粒度。你可以玩一些继承,但增加复杂性大于这种访问限制可能具有的优点。此外,这种方法不会扩展 - 您只能向一个朋友类授予增加的权限。

0

也许有点麻烦,但你可以让嵌套类,其中嵌套类是朋友,那么你可以为每个嵌套类添加好友。这提供了一定程度的粒度:

#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"; 
}