How Non-Member Functions Improve Encapsulation

Question 1

In this case, following Meyers's algorithm will give you member functions:

  • Do they need to be virtual? No.
  • Are they operator<< or operator>>? No.
  • Do they need type conversions? No.
  • Can they be implemented in terms of the public interface? No.
  • So make them members.

His advice is to only make them friends when they really need to be; to favour non-member non-friends over members over friends.

Question 2

The SetXXXX functions need to access the internal (private) representation of the class, so they can't be non-member non-friends; so, Meyers argues, they should be members rather than friends.

The encapsulation comes about by hiding the details of how the class is implemented; you define a public interface separately from a private implementation. If you then invent a better implementation, you can change it without changing the public interface, and any code using the class will continue to work. So Meyers's "number of functions which might be broken" counts the member and friend functions (which we can easily track down by looking at the class definition), but not any non-member non-friend functions using the class through its public interface.

Question 3

This has been answered.

The important points to take away from Meyers's advice are:

  • Design classes to have clean, stable public interfaces separate from their private implementation;
  • Only make functions members or friends when they really need to access the implementation;
  • Only make functions friends when they can't be members.

The meaning f needs type conversions on it left-most arg is as follows:

consider following senario :

Class Integer 
{  
    private: 
       int num;
     public:
        int getNum( return num;)
        Integer(int n = 0) { num = n;}

    Integer(const Integer &rhs)) { num = rhs.num ;}
    Integer operator * (const Integer &rhs)
    {
         return Integer(num * rhs.num);
    }
}


int main()
{
    Integer i1(5);

    Integer i3 = i1 *  3; // valid 

    Integer i3 = 3 * i1 ; // error     
}

In above code i3 = i1 * 3 is equivalent to this->operator*(3) which is valid since 3 is implicitly converted to Integer.

Where as in later i3 = 3 * i1 is equivalent to 3.operator*(i1) , as per rule when u overload operator using member function the invoking object must be of the same class. but here its not that.

To make Integer i3 = 3 * i1 work one can define non-member function as follow :

Integer operator * (const Integer &lhs , const Integer &rhs) // non-member function
    {

         return Integer(lhs.getNum() * rhs.getNum());

    }

I think you will get idea from this example.....