Friends

Table of Contents


1. Friends

Remember that when member variables and functions of a class are set to public they can be accessed by anything and when they are set to private these members can only be accessed from within the class itself.

We can make an exception to this rule by declaring some external function or other class as a friend of the class we're creating. A friend function or class has access to any private or protected members of the class.

Friend function The friend function will be declared within the class' declaration:

class MyClass
{
public:
  void Hi();

private:
  int name;

  friend void PrintMyClass( const MyClass& item );
};

And then it can be defined in a source (.cpp) file elsewhere:

void PrintMyClass( const MyClass& item )
{
  ;; name is private, but this function can access it.
  cout << item.name << endl;
}

Friend class A friend class is the same sort of thing except that any member function of our friend class has access to any private members of the other class.

class ClassWithAFriend
{
private:
  int name;

  friend class FriendlyClass;
};

That other class would be declared elsewhere, and any functions it has can access our ClassWithAFriend's members.

class FriendlyClass
{
public:
  void Display( const ClassWithAFriend& myFriend )
  {
    cout << myFriend.name << endl;
  }
};

However - it doesn't go both ways. Keep in mind that if classA declares that classB is its friend, this means that classB has access to classA's members. However, this does not mean that classA has access to classB's members - we would have to explicitly state "classA is a friend" within the classB class.


Example usage: Unit tests

Using friend is usually considered poor design as you're exposing variables to be modified outside of the class itself. I tend to only use friend for creating a set of unit tests for a given class:

template <typename T>
//! A data structure that wraps a fixed array
class SmartFixedArray : public ILinearDataStructure<T>
{
public:
  // ... etc ...

private:
  /* Private member variables */
  T m_array[100];
  const size_t ARRAY_SIZE;
  size_t m_itemCount;

  // ... etc ...

  friend class SmartFixedArrayTester; // << To make testing easier
};

Then, my unit tests can directly access the private member variables in order to be able to test one function at a time. For example, this test checks the PushAt function, then directly accesses the array to check that the right values are at the right positions, instead of relying on a function like GetAt to see those values. Unit Tests are meant to test one "unit" at a time.

SmartFixedArray<std::string> arr;
arr.m_array[0] = "a";
arr.m_array[1] = "b";
arr.m_array[2] = "c";
arr.m_itemCount = 3;

arr.PushAt( 1, "z" );

if      ( arr.m_array == nullptr )                                              { TestFail(); }
 else if ( !Set_Outputs( "m_itemCount", 4, arr.m_itemCount ) )                  { TestFail(); }
 else if ( !Set_Outputs( "m_array[0]", std::string( "a" ), arr.m_array[0] ) )   { TestFail(); }
 else if ( !Set_Outputs( "m_array[1]", std::string( "z" ), arr.m_array[1] ) )   { TestFail(); }
 else if ( !Set_Outputs( "m_array[2]", std::string( "b" ), arr.m_array[2] ) )   { TestFail(); }
 else if ( !Set_Outputs( "m_array[3]", std::string( "c" ), arr.m_array[3] ) )   { TestFail(); }
 else                                                                           { TestPass(); }

Author: Rachel Wil Sha Singh

Created: 2023-10-05 Thu 20:01

Validate