8

I am working on some code, where I encountered a situation similar to this one:

struct Bar;

struct Foo{
    friend struct Bar;
private:
    Foo(){}
    void f(){}
    void g(){}
};

struct Bar {
   Foo* f;
   Bar()  { f = new Foo();}
   ~Bar() { delete f;}
};

int main(){
  Bar b;
}

I would prefer to have Bar not as friend of Foo, because besides Foos constructor Bar does not need access to any of Foos private methods (and thus should not have access). Is there a way to allow only Bar to create Foos without making them friends?

PS: realized that the question might not be 100% clear. I don't mind if it is via friends or not, just the fact that all Bar has access to all private methods is disturbing me (which is usually the case with friends) and that is what I want to avoid. Fortunately none of the answers given so far had a problem with that lousy formulation.

Cœur
  • 37,241
  • 25
  • 195
  • 267
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185

3 Answers3

9

This is precisely what the attorney-client idiom is for:

struct Bar;

struct Foo {
    friend struct FooAttorney;
private:
    Foo(){}
    void f(){}
    void g(){}
};

class FooAttorney {
  static Foo* makeFoo() { return new Foo; }
  friend struct Bar;
};

struct Bar {
   Foo* f;
   Bar()  { f = FooAttorney::makeFoo();}
   ~Bar() { delete f;}
};

int main(){
  Bar b;
}

In a code imitates life fashion, the class declares an attorney that will mediate the secrets it's willing to share with the selected parties.

Quentin
  • 62,093
  • 7
  • 131
  • 191
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
5

If you do not want to introduce another class, you can shrink the circle of friendship and make Bar's constructor Foo's friend. It requires Bar's definition to be available to Foo, and it still gives Bar's constructor unrestricted access to Foo's private implementation:

struct Foo;

struct Bar {
   Foo* f;
   Bar();
   ~Bar();
};

struct Foo{
    friend Bar::Bar();
private:
    Foo(){}
    void f(){}
    void g(){}
};

Bar::Bar() : f(new Foo()) {
}

Bar::~Bar() {
    delete f;
}

This does not achieve exactly what you want, but it makes friendship a lot more targeted.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • why not exactly what I want? Unfortunately currently `Bar` needs to know `Foo`s definition, but that might change once if fix the friendship issue. – 463035818_is_not_an_ai Mar 29 '17 at 07:10
  • 1
    @tobi303 This isn't exactly what you want, because you asked for restricting what a friend can do, while this approach restricts who is the friend instead. The constructor of `Bar` still retains full range of access due to its friendship with `Foo`. Of course, depending on a situation this may not be a bad thing. – Sergey Kalinichenko Mar 29 '17 at 07:30
  • ah yes, got it. Actually I wouldnt mind if it was possible without friends. I dont like the concept of friends at all (i mean the C++ one ;). With this approach at least the scope where I have to be careful not to do something stupid is limited to its minimum – 463035818_is_not_an_ai Mar 29 '17 at 07:33
3

One way that occurred to me was to have an internal class that makes Bar its friend so only Bar can create it and that internal class can be used as an additional parameter to Foo constructor so only the class's friends can invoke it.

class Foo
{
public:
    // only friends of the special key can invoke the constructor
    // or any member function that includes it as a dummy parameter
    class special_key {friend class Bar; special_key(){}};

    // making special_key a dummy parameter makes sure only friends of
    // the special key can invoke the function
    Foo(special_key) {}
    void f(){}
    void g(){}
};

class Bar
{
public:
    // only Bar functions can create the special key
    Bar() { f = std::make_unique<Foo>(Foo::special_key()); }

private:
    std::unique_ptr<Foo> f;
};

As well as restricting access to specific functions this technique also allows the use of smart pointer make functions which direct friendship does not.

Galik
  • 47,303
  • 4
  • 80
  • 117