如何使一个类只能访问另一个类的某些私有成员?

时间:2012-06-15 15:16:53

标签: c++ class friend

假设我们有两个类:

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不应该弄乱{{1}}的其他成员。

4 个答案:

答案 0 :(得分: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
};

答案 1 :(得分:4)

您可以创建另一个包含Base数据的类,如下所示:

class BaseData {
protected:
    int x;
};

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

现在,Foo可以像f那样访问Base,但不能访问x。友谊不是可交换的。使用protected时,x对所有人都是私密的,除了那些直接来自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

答案 2 :(得分:2)

实现这一目标并非易事,非黑客的方法。 C ++根本就没有这种访问控制粒度。您可以使用一些继承,但增加的复杂性超过了此访问限制可能具有的任何优势。此外,此方法无法扩展 - 您只能将增加的权限授予一个朋友类。

答案 3 :(得分: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";
}