1

And if so, in what situation might this be useful?

Or (and I imagine this is the case), why is it absolutely useless? (What other approach essentially covers the abilities afforded by such friendship, but in a safer and less-leaky way?)

I was in a situation where I almost thought I needed such a thing. I went after an entirely different design in the end, making all the class members static. I'm still curious though.

Andrew Cheong
  • 29,362
  • 15
  • 90
  • 145
  • 2
    Provide protected methods in the base classes would avoid to have so much friends. – Jarod42 Jul 17 '15 at 17:11
  • There's a crucial element missing : *what* are they accessing ? – Quentin Jul 17 '15 at 17:15
  • @Quentin - In my case, I needed to access sibling methods, so if `B` and `C` derive from `A`, I needed to call `B::foo()` from `C::foo()`. In my case these classes encapsulate different algorithms (so the Strategy pattern comes to mind...) but sometimes one algorithm would use a substantial portion of another algorithm. Yet, it didn't seem correct to derive `C` from `B`, because `C` doesn't really have an "is-a" relationship with `B`. – Andrew Cheong Jul 17 '15 at 17:24

3 Answers3

3

Is there a way to make all derived classes friends of one another?

The language does not provide any mechanism to specify something like this in a base class. You'll have to provide the friend declarations in every class you inherit from the base class.

I am not able to suggest anything more positive since I don't know the problem you are trying to solve.

In a comment, you said:

In my case, I needed to access sibling methods, so if B and C derive from A, I needed to call B::foo() from C::foo(). In my case these classes encapsulate different algorithms (so the Strategy pattern comes to mind...) but sometimes one algorithm would use a substantial portion of another algorithm. Yet, it didn't seem correct to derive C from B, because C doesn't really have an "is-a" relationship with B.

If C doesn't have an "is-a" relationship with B, yet C::foo() somehow needs to call B::foo(), it indicates to me that B::foo() can only use data that is common to both B and C. In that case, it should be possible to factor out the code into a non-member function and then use it from B::foo() and C::foo().

Change the dependency from:

B::foo()
   ^
   |
C::foo()

to

 <some namespace>::foo()
          ^
          |
  +-------+---------+
  |                 |
B::foo()          C::foo()
R Sahu
  • 204,454
  • 14
  • 159
  • 270
3

C++ only gives you two ways to name friends:

friend class C; // a specific class

template <typename T>
friend class S; // friend the class template S

There's no way to stick in a metafunction in there, which would look hypothetically something like this:

template <typename T>
friend enable_if_t<std::is_base_of<Base, T>::value, T>;

But I guess if you're open to horrible hackery (this phrase should be interpreted as never do this ever please god no, but it's at least marginally amusing), you could simply implement all of your derived types as explicit specializations of some template.

struct Base { ... };

template <typename > class Derived;

struct A_tag { };

template <>
class Derived<A_tag> : Base {
    template <typename T>
    friend class Derived;

    ...
};

using A = Derived<A_tag>;

If we do similar thing for B, C, etc., then A, B, and C are mutually all friends - since under the hood they're really Derived<A_tag>, Derived<B_tag>, and Derived<C_tag> and thus the friend class template statement covers all of them.

Barry
  • 286,269
  • 29
  • 621
  • 977
3

Not friend exactly, but you may be able to restrict access using some variant of the Passkey pattern

If you create a protected inner Passkey class in your base class. Any derived classes can then restrict access to siblings by requiring the Passkey as a parameter:

class A {
protected:
  class Passkey {};
};

class B : public A {
public:
  void someProtectedFunction(Passkey) {};
};

class C : public A {
public:
  void somePublicFunction() {
    B b;
    b.someProtectedFunction(A::Passkey{});
  }
};

int main() {
  C c;
  c.somePublicFunction();

  B b;
  //b.someProtectedFunction(A::Passkey{});  // error: `class A::Passkey` is protected
}
Community
  • 1
  • 1
Chris Drew
  • 14,926
  • 3
  • 34
  • 54