简体   繁体   中英

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

Suppose we have two classes:

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

class Foo
{
    // some variables and methods
};

Now everyone can call Base::f() , but I want only Foo to be able to do so.

In order to achieve this effect, we can make Base::f() private and declare Foo as a friend:

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

The problem with this approach is that Foo has the access to both Base::f() and Base::x (and even to any other private members of Base ). But I want Foo to have access only to Base::f() .

Is there a way for a class (or a function) to grant an access only to certain private members of another class? Or maybe anyone could suggest a better approach to my problem?

EDIT:

I'll try to specify the access restriction I need. Firstly, Base is an interface in a library (it's an abstract class, in fact). The user uses only the classes derived from Base . Base::f() is called only by Foo which is another class in the library. Hiding Base::f() from the user is important, because only Foo knows when to call it. At the same time, Foo shouldn't mess up the other members of Base .

Very hacky, but this will allow very fine grained access.

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

You can create another class that contains the data for Base like this:

class BaseData {
protected:
    int x;
};

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

Now, Foo can access f as a method of Base like you wanted, but not x . Friendship is not commutative. By using protected , x appears private to everyone except those that derived directly from BaseData .

A better approach might be to use multiple inheritance to define Base , and provide Foo access only to those classes you want from which Base derives.

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

Here, Foo would have to have a With_f pointer to Base , but it could then access the f method. Foo could not access g .

There's no easy, non-hackish way to achieve that. C++ simply doesn't have such access control granularity. You can play with some inheritance, but increased complexity outweighs any advantages this access restriction might have. Also, this approach doesn't scale - you can grant increased permissions only to one friend class.

Maybe a bit cumbersome, but you could make nested classes where the nesting class is friend, then you can add friends per nested class. This gives some level of granularity:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM