1

Suppose that I have these classes:

class Bar;
class Foo {
    private:
        // stuff here
    public:
        void methodForClassBar();
};

What I want to do is make methodForClassBar private in a way that class Bar still be able to call it. But I don't want class Bar to be able to access any other private members of Foo.

My current solution is this: put methodForClassBar into private, and create an accessor class (FooInterfaceToClassBar, this can only be accessed by Bar), which is a friend to Foo. So with this accessor class, I can call methodForClassBar:

class FooInterfaceToClassBar;

class Foo {
    private:
        // stuff here
    private:
        void methodForClassBar();

        friend FooInterfaceToClassBar;
};

class FooInterfaceToClassBar {
    private:
        static void inline callMethod(Foo &foo) {
            foo.methodForClassBar();
        }

        friend class Bar;
};

void Bar::someMethod(Foo &foo) {
    FooInterfaceToClassBar::callMethod(foo);
}

Is there a other/better (more convenient) method to achieve this, without any runtime performance cost (I'd like to avoid adding interfaces with virtual methods)?

Christophe
  • 68,716
  • 7
  • 72
  • 138
geza
  • 28,403
  • 6
  • 61
  • 135
  • You can additionally make `callMethod` private and make `Bar` a friend of `FooInterfaceToClassBar`. Also a need for such a sneek method might indicate a potential problem with class structure organization and distribution of responsibilities. – user7860670 Oct 01 '17 at 18:04
  • @VTT: Thanks! As I've reread my question, and just as your comment arrived, I've realized this too :) I've reworded the question, but maybe it is not interesting anymore. – geza Oct 01 '17 at 18:08
  • Yep, this is the "Attorney-Client Idiom", as I know its name now. Good to know. – geza Oct 01 '17 at 18:36

1 Answers1

2

You can restrict the access to the interface's method to only Bar in this way:

class FooInterfaceToClassBar {
private: 
    FooInterfaceToClassBar() = delete;    // avoid accidental instantiation
    static void inline callMethod(Foo &foo) {
        foo.methodForClassBar();
    }
    friend class Bar;
};

Although a little inconvenient, this approach gives the most precise control on the visibility, with the minimum of overhead. A variant could be to make the interface class a nested class of Foo. But the only advantage is not to clutter the namespace.

Other approaches

Another approach could be to use inheritance. However, single inheritance will not really do the trick : it can easily give more access to Bar's privacy than expected.

If methodForClassBar() doesn't need itself to access other private stuff, you could isolate it for the Bar access using multiple inheritance. This approach requires however heavy contraints and is not as flexible as yours:

class Foo0 {
    //...    // the real private stuff goes here 
};
class Foo1 {
    private:
        void methodForClassBar();
        friend Bar; 
};
class Foo : public Foo0, public Foo1 {
    //...
}; 
...
void Bar::someMethod(Foo &foo) {
   foo.methodForClassBar();
}

Furthermore, if you can isolate the method so easily from the rest, you could as well do the same things directly within the Bar method, which makes this alternative look a little bit clumsy.

Christophe
  • 68,716
  • 7
  • 72
  • 138
  • Yes, thank you. I've realized this, and edited my question. I'm sorry about this. But I'm still interested in other solutions (if exists), because this is inconvenient. I'll give you an upvote anyway, of course :) – geza Oct 01 '17 at 18:16
  • @geza There are in my opinion not so much alternatives if you want to control precisely the visibility of different functions to different classes. See edit. – Christophe Oct 01 '17 at 20:12
  • Using multiple inheritance can be a good idea, I'll keep it in mind (I cannot use it for my current problem, but maybe it can be useful in the future) - If we lift the non-virtual-method limit, using MI can be useful in a lot of cases. But I don't want this because of the performance cost (which is actually significant in my current case unfortunately). I'll keep using this "Attorney-Client" Idiom. – geza Oct 01 '17 at 20:22