1

I would like to implement a Containerclass that can only be accessed by the classes I want, in a way similar to the following

class ContainerAccess {
    // empty 
};

class Container{
  private:
    static void _do_stuff();
    static int _value;

    friend class ContainerAccess;
};

Now I want to have access to the Container data as follows:

class Processor: public ContainerAccess {
  public:
    void proccess() {
      Container::_do_stuff();
      Container::_value++;
    }
};

However, this does not work. Why is that? And how could that be done?

manatttta
  • 3,054
  • 4
  • 34
  • 72
  • 4
    That does not and will not work because friendship is not [**inherited**, transitive, or reciprocal](http://www.parashift.com/c++-faq/friendship-not-inherited-transitive.html). – Captain Obvlious Dec 15 '14 at 15:26
  • 2
    Friendship is not inherited. http://stackoverflow.com/questions/3561648/why-does-c-not-allow-inherited-friendship – japreiss Dec 15 '14 at 15:26
  • how could I do this then? – manatttta Dec 15 '14 at 15:29
  • 1
    @manatttta _"how could I do this then?"_ Use connected abstract interfaces for `Container` and `ContainerAccess` derivates. – πάντα ῥεῖ Dec 15 '14 at 15:30
  • @πάνταῥεῖ thanks. do you have any link with more detailed info? – manatttta Dec 15 '14 at 15:35
  • Why `Container` and `ContainerAccess` are separate classes? I do not see any reason. That static members can be in class `ContainerAccess` and that would not change anything, except remove your problem. Your design is pretty strange at least. Did you come from different language? – Slava Dec 15 '14 at 15:38
  • 1
    @Slava There's nothing wrong with this design. You could have Container class which is meant to provide features to several classes. – ravi Dec 15 '14 at 15:40
  • 1
    If that worked it would not be _limiting_ access to a specific set of classes but to everything that derives from `ContainerAccess`. By attempting to provide friendship to `ContainerAccess` and allowing anyone to inherit from it you have effectively injected an additional step to gain what is already provided by declaring the members `public` or `protected`. You should really rethink what you are trying to accomplish. – Captain Obvlious Dec 15 '14 at 15:46
  • @manatttta _"do you have any link with more detailed info?"_ Yes, I have now. That's the essence how to refactor a friend relationship, that I once wrote up in an article, and now provided as a Q&A here: [**How can I remove/refactor a friend declaration properly?**](http://stackoverflow.com/questions/27492132/how-can-i-remove-refactor-a-friend-declaration-properly) – πάντα ῥεῖ Dec 15 '14 at 20:04

2 Answers2

1

Your approach is wrong as friendship is not inherited. However, there is a good way to solve what you are trying to solve and that's private inheritance.

class Container
{
  protected:
    static void _do_stuff();
    static int _value;
};


class ContainerAccess : private Container 
{
    //using _do_stuff();
};

This way you can chose whatever classes need to use class Container at the same time you also prevent other users from using your class.

ravi
  • 10,994
  • 1
  • 18
  • 36
-2

A possible alternative would be to not make the methods of Container private static, but instead make them only public.

Then, in your main function, create a single instance of Container, and pass it around to methods/classes who need access to the functionality provided by Container.

class Processor {
  public:
    void process(Container & container) {
      container.do_stuff();
      container.value++;
    }
};

The methods who you do not give an instance of Container cannot then operate.

Svalorzen
  • 5,353
  • 3
  • 30
  • 54
  • I don't see how making `Container`'s methods public lends itself to good encapsulation, nor how this suggestion really helps the OP do what he wants. – caps Dec 15 '14 at 17:05
  • @caps The point is to make them public, but not static - possibly giving Container only a private constructor similar to a non-globally-accessible Singleton. Then, access is restricted to those who get passed the instance. Operations are public, but restricted on instance, rather than operations are accessible everywhere, but restricted on friendship. – Svalorzen Dec 15 '14 at 17:10
  • @Svalorzen No! Making the methods public, certainly isn't the correct/appropriate solution. One should have a (non publicly visible) interface for the client classes in this case. See the Q&A I have linked in my comment on the question. It's a more general approach about how to get rid of «friend» relationships. – πάντα ῥεῖ Dec 15 '14 at 20:29
  • @πάνταῥεῖ If you could possibly hint as to why this solution is incorrect, rather than just stating so, I guess your comment would be more useful. I fail to see how my solution fails to restrict access to functionality only to facilities which are provided with the `Container` instance. – Svalorzen Dec 16 '14 at 07:56
  • @Svalorzen If you use friend, there's usually a reason to keep the declaring classes' interface private, isn't it? So simply making it public isn't an equivalent solution. – πάντα ῥεῖ Dec 16 '14 at 07:59
  • @πάνταῥεῖ I'm not sure, I guess what matters is the result, right? If the practical result is the same - code which does not have access to an instance does not have access to the functionality - and not having access to it means it does not depend on it, which is the point. Also, the fact that an interface is public does not mean that in necessarily gets included in all the code, unless you explicitly `#include` it. `public` does not suddenly become an evil just because. Again, the practical result is equivalent, so I stand by my answer. – Svalorzen Dec 16 '14 at 08:09