1

I have a class Widget with some private internals, but I would like to expose these internals to predicate functors (only) via friendship.

class Widget
  {
  ComponentA a;
  ComponentB b;
  friend class WidgetPredicate;
  };

class WidgetPredicate : public std::unary_function<bool, const Widget&>
  { 
  bool operator () (const Widget& w) const
    {
    // inspect a and b and make a yes/no decision 
    }
  };

The intent is that I can use the WidgetPredicate function as a sifter in all the std::xxxx_if family of algorithms.

However, I would like to leave some extensibility in the system where a future developer could make new predicates that somehow inheirit the friend status neatly. Is there a good design idiom for this? My current (non) solution is that everything in Widget is public.

I tried toying around with a base class that exposed the internals of Widget to subtypes of WidgetPredicate through protected functions, something like:

class WidgetPredicate : public std::unary ...
  {
  protected:
    const ComponentA& expose_a ( const Widget& w ) const { return w.a; }
    const ComponentB& expose_b ( const Widget& w ) const { return w.b; }
  public:
    virtual bool operator () ...
  };

class DerivedWidgetPredicate : public WidgetPredicate
  {
  public:
    virtual bool operator () (const Widget& w)
      {
      const ComponentA& a = this->expose_a(w); // a can now be inspected/predicated upon
      const ComponentB& b = this->expose_b(w); // b ...
      }
  };

I can live with the potential that now any class could examine Widget's internals just by saying :public WidgetPredicate. I am not trying to protect against malicious developers, so if they say they're a friendly WidgetPredicate then I am willing to take that at face value. The syntax is also subpar, but I can live with that too. What I don't like the maintainence issue, that when I change the internals of Widget I have to also add new expose() methods to the base predicate. (IMO That process could and should be mechanical).

I could always put the expose methods directly in the Widget class, but IMO at that point I might as well make the fields public and just live with it (ie my current soln).

RAC
  • 4,979
  • 3
  • 21
  • 10

1 Answers1

2

While it is more expensive, you should define what operations can be allowed for external code and implement them. If you do not want to offer those operations in your public/protected interface, the solution you have posted (declaring another class as a friend and using it as a proxy into your internal code) is a fine solution.

This is subjective, and probably an unwanted comment, but anyway... There is no such thing as a good design mechanism for exposing class internals.

< irony>Just make everything public < /irony>

What you are doing is developing a complex mechanism to break your encapsulation. After you are done with it, all code can access your private members. You state that only predicate functors will have access to the members, but you cannot block non-predicate classes from deriving from the predicate type just to acquire access to the data.

One of the points of encapsulation is reducing dependencies: external code only depend on the public interface, you can always change your internal types and representation and external code will not break (external as not class or friend code). Now, after you have exposed (directly or indirectly) your internals, then those are now part of your public interface and must thus be frozen.

Another point of encapsulation is that you can guarantee invariants on the internal data. After external code have access to the internals, there is no way you can control any kind of invariant on your methods (say keeping the max_size field of a container to the size of the acquired memory) and your class can break due to others misuse.

There are reasons for friendship not being transitive nor inherited: when you declare a class to be a friend of your class, you can check the behavior of that class (and in most cases you are in full control of the friend class). You know that the code you are giving access to does not break your own code.

class Widget
{
   friend class BackDoor; // assume that you have implemented it
};
class MaliciousClass1 // third class, malicious or not cannot break into Widget
{
};
class MaliciousClass2 : public BackDoor // You cannot block external code from deriving from BackDoor 
{
   // Can break into your widget, access and modify anything
};

The door is open for any and everyone to play with your private parts.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • A very nice and accurate answer! +1 from me. – Paolo Tedesco Jul 20 '09 at 11:24
  • minor note: you can block deriving by using a private ctor and a public static factory function to create BackDoor objects, IIUC. – Macke Jun 15 '10 at 08:30
  • @Marcus Lindblom: There are different ways of blocking inheritance, including but not limited to yours. But I do not see how that relates to this answer, since friendship is *not* transitive nor inheritable. Another approach to blocking inheritance that does not require writing static methods for each constructor can be seen here: http://stackoverflow.com/questions/656224/when-should-i-use-c-private-inheritance/656523#656523 – David Rodríguez - dribeas Jun 15 '10 at 09:21