3

I have a nested class in c++ which has to be public. But I need some of its methods visible to the outer world, and the rest visible only to the nesting class. That is:

class set {
public:
    class iterator {
        innerMethod();
    public:
        outerMethod();
    }
}

I want to be able to write a method for set which uses innerMethod(). If I make it public, I can access it from outside as well, which is something that I definitely don't want. Is there a way to do it without doing the "friend class set" thing?

Thanks in advance!

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 4
    Why don't you want to use `friend` declarations? – finnw Jan 13 '11 at 12:28
  • Not really sure why you call it a "friend class set" in quotes. Just to be clear, you can use `friend` exactly the same way you use `public`, which doesn't seem to bother you. – Cody Gray - on strike Jan 13 '11 at 12:34
  • 2
    This is exactly the sort of case where `friend` declarations *improve* encapsulation, since the obvious alternative is to break encapsulation entirely. – aschepler Jan 13 '11 at 12:53
  • Maybe in this case it's not about friend or not friend. Maybe your design is not ok. Please do not reimplement set. The STL library provides one already. – ds27680 Jan 13 '11 at 13:09
  • @ ds27680 - I need to implement it for class. In real life, no way I'm going to write my own Set class if I have it in the STL library. – Mockingbird Jan 15 '11 at 08:23

5 Answers5

2

There is NO GOOD WAY you can do this, without using friend keyword.

In the comment you said:

In the programming class I currently take, using 'friend' was said to be ill-advised and generally considered "bad programming" for the most part, unless there is really no other way around it. So I try to avoid it as much as possible.

friend breaks encapsulation, maybe that is the reason why your class teacher said it's bad-programming. But member-functions too break encapsulation, then why do you use them? Why not avoid them too? friend breaks encapsulation in the same way as do member-functions; so if you're comfortable using member-functions when they're needed, then you should be comfortable using friend also when they're needed. Both exist in C++ for a reason!

class set {
public:
 class iterator 
 {
  friend class set; //<---- this gives your class set to access to inner methods!

  void innerMethod(){}
 public:
  void outerMethod(){}
 };
 iterator it;

 void fun()
 {
  it.innerMethod();
  it.outerMethod();
 }
};

See this : How Non-Member Functions Improve Encapsulation

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    I would't say NO WAY. Rather "no easier"... I bet I can have the method private, not use friend and call it nevertheless from the outer class. But it certainly would not be a good idea... – ds27680 Jan 13 '11 at 12:46
  • Actually there is. It's relatively confidential though, but I have been advocating a few times already on SO. It's not specific to nested classes either. I've added an answer that I hope will get closer to the top in which I describe the use of Keys, which is a bit different from the Proxys or Advocate patterns. – Matthieu M. Jan 13 '11 at 14:25
  • The point of encapsulation, is not to prevent the user from using your class, but give it controlled access to the class members, and a set of pre-defined functions/methods to do with it, which are done the way _you_ want, not the user. For example: In a class of a rational number, you'd prevent the user from directly access the denominator, and give it a contractor which throws an exception when the user of this class tries to pt zero in the denominator. – Mockingbird Jan 15 '11 at 08:29
  • @Mokingbird: Yes. I didn't say encapsulation is to "prevent" user from using it. What's your point? – Nawaz Jan 15 '11 at 08:34
1

No, I don't think there are other non-hacky methods but using the friend-directive.

friend exists right for this kind of purpose, why would you avoid it?

peoro
  • 25,562
  • 20
  • 98
  • 150
  • In the programming class I currently take, using 'friend' was said to be ill-advised and generally considered "bad programming" for the most part, unless there is _really_ no other way around it. So I try to avoid it as much as possible. – Mockingbird Jan 13 '11 at 12:36
  • @Mokingbird: `friend` breaks encapsulation, maybe that is the reason why your class teacher said it's bad styles. But member-functions too break encapsulation, why you use them? – Nawaz Jan 13 '11 at 12:40
  • 1
    @Mokingbird: Sounds like a good opportunity to ask questions. I for one am very curious why anyone would say `friend` was *bad* programming practice. Obviously, like anything else, it should be used with caution rather than to enable a poorly conceived OO design, but there's nothing inherently wrong with its use when you need it. Also see the [C++ FAQ on `friend`](http://www.parashift.com/c++-faq-lite/friends.html). – Cody Gray - on strike Jan 13 '11 at 12:40
  • @Nawaz - why would member-function break encapsulation? – Mockingbird Jan 13 '11 at 12:45
  • 1
    @Nawaz, you are wrong, `friend` *enhances* encapsulation. And people who say that `friend` is bad style haven’t understood its purpose. It’s true that it’s not often useful, but sometimes it is. – Konrad Rudolph Jan 13 '11 at 12:47
  • @Cody Gray - making something outside a class a friend takes the implementation of parts of the class outside it, and makes it harder to maintain on the long run. Usually it is not really necessary to declare friends, and there's a way around it. Or so we are told. – Mockingbird Jan 13 '11 at 12:56
  • @Mokingbird: If that were true, then `public` methods would also be banned. Obviously they're not. From the link I posted above: "Many people think of a friend function as something outside the class. Instead, try thinking of a friend function as part of the class's public interface. A friend function in the class declaration doesn't violate encapsulation any more than a public member function violates encapsulation: both have exactly the same authority with respect to accessing the class's non-public parts." – Cody Gray - on strike Jan 13 '11 at 13:00
  • @Mokingbird: Iterators are like an "extension" of their respective container class. Think of iterators as a subset of the container API with added state information (the position within the container). Iterators/containers are therefore intimately interconnected. Friend is ideal for just this sort of thing. – Emile Cormier Jan 13 '11 at 13:07
1

Try asking: is there any way to add 2 numbers without adding them? Sorry if I'm harsh, but friend class is for exactly that...

peenut
  • 3,366
  • 23
  • 24
1

Yes there is.

I've been trying to advocate the method for a while now, the basic idea is to use a Key class.

While this does not actually remove the use of friend, it does reduce the set of exposed implementations details.

class set;

// 1. Define the Key class
class set_key: noncopyable { friend class set; set_key() {} ~set_key() {} };

class set
{

  // 2. Define the iterator
  class iterator
  {
  public:
    void public_method();

    void restricted_method(set_key&);

  }; // class iterator

}; // class set

Now, restricted_method is public, so set does not need any special access to iterator. However the use of it is restricted to those able to pass a set_key instance... and conveniently only set may build such an object.

Note that set may actually pass a set_key object to someone else it trusts. It is a key in the traditional sense: if you give a key of your flat to someone, it may entrust it to another person. However because of the semantics of the key class (non copyable, only set may construct and destroy it) this is normally limited to the duration of the scope of the key object.

Note that a evil hack is always possible, namely *((set_key*)0). This scheme protects from Murphy, not Machiavelli (it's impossible in C++ anyway).

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
0

You can do something like this:

class set

{

public:
    class iterator
    {
        protected:
            iterator(){};
            virtual ~iterator(){};

        public:
            //outer world methods...
    };

private:
    class privateIterator : public iterator
    {
        public:
            privateIterator(){};
            ~privateIterator(){}

        //inner methods;
    };

public:
    iterator* CreateIterator()
    {
        return new privateIterator();//this is used to be sure that you only create private iterator instances
    }

};

I don't know if it's the right answer, but it does now uses friend key work and it hides some of the methods. The only problem is that you can't declare privateIterator and you always must use CreateIterator to create an instance...

Mircea Ispas
  • 20,260
  • 32
  • 123
  • 211