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

How to make a class able to access only certain private members of another class?

本文关键字:成员 访问 何使一 另一个      更新时间:2023-10-16

假设我们有两个类:

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的其他成员。

非常笨拙,但这将允许非常细粒度的访问。

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

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

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

现在,Foo可以访问f作为您想要的Base方法,但不能x。友谊不是交换的。通过使用 protected ,除了那些直接派生自BaseDatax之外,对所有人都是私有的。

更好的方法可能是使用多重继承来定义Base,并且仅提供对Base派生自的那些类的Foo访问。

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必须有一个指向BaseWith_f指针,但它可以访问f方法。 Foo无法访问g

没有简单、非黑客的方法来实现这一点。C++根本没有这样的访问控制粒度。您可以使用一些继承,但增加的复杂性超过了此访问限制可能具有的任何优势。此外,此方法无法扩展 - 您只能向一个友元类授予增加的权限。

也许有点麻烦,但是您可以创建嵌套类是友元的嵌套类,然后您可以为每个嵌套类添加好友。 这提供了一定程度的粒度:

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