2021/8/8 Encapsulation | Helper Functions
https://ict.senecacollege.ca/~oop244/pages/content/nonme.html 1/9
ICT Home Outline Timeline Notes IPC Notes MySeneca Workshops Assignments Instructor
Software
Development
OOP244
Part C – Encapsulation
Helper Functions
Support a class definition with global function definitions
Describe the syntax for overloading operators that support a class
Grant a global function access to the private members of a class
“Avoid membership fees: Where possible, prefer making functions nonmember non-friends”
(Sutter, Alexandrescu, 2005)
Free | Operators | Friends | Summary | Exercise
In object-oriented programming, not all instructions that support a class need to be included in the class definition. A well-
encapsulated class can accept external support in the form of global functions containing additional logic. We call these functions
helper functions. Helper functions access the objects of a class solely through their parameters, all of which are explicit. A
typical helper function includes at least one parameter of the class type that it supports.
This chapter describes the definition of helper functions, including helper operators, and discusses the granting of privileged
access to the private members of a class.
FREE HELPERS
A free or loosely coupled helper function is a function that obtains all of its information from the public member functions of the
class that it supports. A free helper function does not require access to the private members of its class. The coupling between a
free helper function and its class is minimal, which is an ideal design solution.
Comparison
Consider a helper function that compares two objects of the same class. The function returns true if the objects have the same
data values and false if they differ.
Example
Let us add three queries (getStudentNo(), getNoGrades() and getGrade()) to our Student class definition and a
helper function named areIdentical() as support. For conciseness, let us assume that all grades are stored in static memory.
We insert the prototype for our helper function into the header file after the class definition:
// Student.h
const int NG = 20;
class Student {
int no;
float grade[NG];
int ng;
public:
Student();
Student(int);
Student(int, const float*, int);
void display() const;
int getStudentNo() const { return no; }
int getNoGrades() const { return ng; }
float getGrade(int i) const { return i < ng ? grade[i] : 0.0f; }
};
Welcome
Notes
Welcome to OO
Object Terminology
Modular Programming
Types Overloading
Dynamic Memory
Member Functions
Construction
Current Object
Member Operators
Class + Resources
Helper Functions
Input Output
Derived Classes
Derived Functions
Virtual Functions
Abstract Classes
Templates
Polymorphism
I/O Refinements
D C + Resources
Standards
Bibliography
Library Functions
ASCII Sequence
Operator Precedence
C++ and C
Workshops
Assignments
Handouts
Practice
Resources
https://ict.senecac.on.ca/
https://ict.senecacollege.ca/~oop244/index.html
http://www.senecacollege.ca/ssos/findwithoutsemester/oop244/sict
https://ict.senecacollege.ca/~oop244/pages/timeline.html
https://ict.senecacollege.ca/~oop244/pages/content/index.html
https://scs.senecac.on.ca/~ipc144/pages/content/index.html
https://my.senecacollege.ca/webapps/portal/frameset.jsp
https://ict.senecacollege.ca/~oop244/dynamic/workshops/index.html
https://ict.senecacollege.ca/~oop244/pages/assignments/index.html
https://ict.senecacollege.ca/~oop244/pages/instructors/index.html
https://ict.senecacollege.ca/~oop244/pages/content/nonme_p.html
https://ict.senecacollege.ca/~oop244/pages/welco.html
https://ict.senecacollege.ca/~oop244/pages/content/index.html
https://ict.senecacollege.ca/~oop244/pages/content/langu.html
https://ict.senecacollege.ca/~oop244/pages/content/objec.html
https://ict.senecacollege.ca/~oop244/pages/content/compi.html
https://ict.senecacollege.ca/~oop244/pages/content/rudim.html
https://ict.senecacollege.ca/~oop244/pages/content/dynam.html
https://ict.senecacollege.ca/~oop244/pages/content/cppst.html
https://ict.senecacollege.ca/~oop244/pages/content/ctors.html
https://ict.senecacollege.ca/~oop244/pages/content/membe.html
https://ict.senecacollege.ca/~oop244/pages/content/overl.html
https://ict.senecacollege.ca/~oop244/pages/content/deepc.html
https://ict.senecacollege.ca/~oop244/pages/content/nonme.html
https://ict.senecacollege.ca/~oop244/pages/content/custo.html
https://ict.senecacollege.ca/~oop244/pages/content/inher.html
https://ict.senecacollege.ca/~oop244/pages/content/dfunc.html
https://ict.senecacollege.ca/~oop244/pages/content/inclu.html
https://ict.senecacollege.ca/~oop244/pages/content/abstr.html
https://ict.senecacollege.ca/~oop244/pages/content/param.html
https://ict.senecacollege.ca/~oop244/pages/content/adhoc.html
https://ict.senecacollege.ca/~oop244/pages/content/basic.html
https://ict.senecacollege.ca/~oop244/pages/content/dclas.html
https://ict.senecacollege.ca/~oop244/pages/content/ansis.html
https://ict.senecacollege.ca/~oop244/pages/content/bibli.html
https://ict.senecacollege.ca/~oop244/pages/content/libraries.html
https://ict.senecacollege.ca/~oop244/pages/content/ascii.html
https://ict.senecacollege.ca/~oop244/pages/content/prece.html
https://ict.senecacollege.ca/~oop244/pages/content/c_cpp.html
https://ict.senecacollege.ca/~oop244/dynamic/workshops/index.html
https://ict.senecacollege.ca/~oop244/pages/assignments/index.html
https://ict.senecacollege.ca/~oop244/pages/handouts/index.html
https://ict.senecacollege.ca/~oop244/pages/practice/index.html
https://ict.senecacollege.ca/~oop244/pages/resources/index.html
2021/8/8 Encapsulation | Helper Functions
https://ict.senecacollege.ca/~oop244/pages/content/nonme.html 2/9
bool areIdentical(const Student&, const Student&);
The implementation file contains the definition of our helper function.
// Student.cpp
#include
using namespace std;
#include “Student.h”
Student::Student() {
no = 0;
ng = 0;
}
Student::Student(int n) {
*this = Student(n, nullptr, 0);
}
Student::Student(int sn, const float* g, int ng_) {
bool valid = sn > 0 && g != nullptr && ng_ >= 0;
if (valid)
for (int i = 0; i < ng_ && valid; i++)
valid = g[i] >= 0.0f && g[i] <= 100.0f;
if (valid) {
// accept the client's data
no = sn;
ng = ng_ < NG ? ng_ : NG;
for (int i = 0; i < ng; i++)
grade[i] = g[i];
} else {
*this = Student();
}
}
void Student::display() const {
if (no > 0) {
cout << no << ":\n";
cout.setf(ios::fixed);
cout.precision(2);
for (int i = 0; i < ng; i++) {
cout.width(6);
cout << grade[i] << endl;
}
cout.unsetf(ios::fixed);
cout.precision(6);
} else {
cout << "no data available" << endl;
}
}
bool areIdentical(const Student& lhs, const Student& rhs) {
bool same = lhs.getStudentNo() == rhs.getStudentNo() &&
lhs.getNoGrades() == rhs.getNoGrades();
for (int i = 0; i < lhs.getNoGrades() && same; i++)
same = lhs.getGrade(i) == rhs.getGrade(i);
return same;
}
The following client code compares the two objects:
// Compare Objects
// compare.cpp
#include
#include “Student.h”
using namespace std;
int main () {
2021/8/8 Encapsulation | Helper Functions
https://ict.senecacollege.ca/~oop244/pages/content/nonme.html 3/9
float gh[] = {89.4f, 67.8f, 45.5f};
Student harry(1234, gh, 3), harry_(1234, gh, 3);
if (areIdentical(harry, harry_))
cout << "are identical" << endl;
else
cout << "are different" << endl;
}
are identical
The Cost of Upgrading Freedom
Free helper functions use public queries to access information that is otherwise inaccessible. If we add a data member to the class,
we may also need to add a query to access its value. As we add data members, the class definition grows with new queries. We
call this growth class bloat.
One alternative to class bloat that admits upgradability is friendship (see below).
HELPER OPERATORS
Helper operators are global functions that overload operators. Candidates for helper operators are operators that do not change the
values of their operands as shown in the table below.
Effect on Operand(s) Candidate Operands Operator
Left Operand Changes Member
0 ++ -- - + ! & *
1 = += -= *= /= %=
Neither Operand Changes Helper 2 + - * / % == != >= <= > < << >>
Identity Comparison
To improve readability, let us replace the areIdentical() function defined above with an overloaded == operator that takes
two Student operands. The header file for the Student class now contains:
// Student.h
const int NG = 20;
class Student {
int no;
float grade[NG];
int ng;
public:
Student();
Student(int);
Student(int, const float*, int);
void display() const;
int getStudentNo() const { return no; }
int getNoGrades() const { return ng; }
float getGrade(int i) const { return i < ng ? grade[i] : 0.0f; }
};
bool operator==(const Student&, const Student&);
The implementation file contains defines this helper operator:
bool operator==(const Student& lhs, const Student& rhs) {
bool same = lhs.getStudentNo() == rhs.getStudentNo() &&
lhs.getNoGrades() == rhs.getNoGrades();
for (int i = 0; i < lhs.getNoGrades() && same; i++)
same = lhs.getGrade(i) == rhs.getGrade(i);
return same;
}
The following client code compares the two objects:
2021/8/8 Encapsulation | Helper Functions
https://ict.senecacollege.ca/~oop244/pages/content/nonme.html 4/9
// Compare Objects
// compare.cpp
#include
#include “Student.h”
using namespace std;
int main () {
float gh[] = {89.4f, 67.8f, 45.5f};
Student harry(1234, gh, 3), harry_(1234, gh, 3);
if (harry == harry_)
cout << "are identical" << endl;
else
cout << "are different" << endl;
}
are identical
Addition
Consider an expression that adds a single grade to a Student object and evaluates to a copy of the updated object. To
implement this operation, let us overload the + operator for a Student object as the left operand and a float as the right
operand.
As part of the class definition, we include the += operator described in the preceding chapter on Member Operators. The header
file for the Student class now contains:
// Student.h
const int NG = 20;
class Student {
int no;
float grade[NG];
int ng;
public:
Student();
Student(int);
Student(int, const float*, int);
const Student& operator+=(float);
void display() const;
int getStudentNo() const { return no; }
int getNoGrades() const { return ng; }
float getGrade(int i) const { return i < ng ? grade[i] : 0.0f; }
};
bool operator==(const Student&, const Student&);
Student operator+(const Student&, float);
We maintain loose coupling by initializing a new Student object to the left operand and calling the += member operator on that
object to add the single grade:
Student operator+(const Student& s, float grade) {
Student copy = s; // makes a copy
copy += grade; // calls the += operator on copy
return copy; // return updated copy
}
For symmetry, we overload the addition operator for identical operand types but in reverse order. The complete header file
contains:
// Student.h
const int NG = 20;
class Student {
int no;
float grade[NG];
int ng;
public:
https://ict.senecacollege.ca/~oop244/pages/content/overl.html#bin
2021/8/8 Encapsulation | Helper Functions
https://ict.senecacollege.ca/~oop244/pages/content/nonme.html 5/9
Student();
Student(int);
Student(int, const float*, int);
const Student& operator+=(float);
void display() const;
int getStudentNo() const { return no; }
int getNoGrades() const { return ng; }
float getGrade(int i) const { return i < ng ? grade[i] : 0.0f; }
};
bool operator==(const Student&, const Student&);
Student operator+(const Student&, float);
Student operator+(float, const Student&);
Our implementation calls the first version with the arguments reversed:
// Student.cpp
#include
using namespace std;
#include “Student.h”
Student::Student() {
no = 0;
ng = 0;
}
Student::Student(int n) {
float g[] = {0.0f};
*this = Student(n, g, 0);
}
Student::Student(int sn, const float* g, int ng_) {
bool valid = sn > 0 && g != nullptr && ng_ >= 0;
if (valid)
for (int i = 0; i < ng_ && valid; i++)
valid = g[i] >= 0.0f && g[i] <= 100.0f;
if (valid) {
// accept the client's data
no = sn;
ng = ng_ < NG ? ng_ : NG;
for (int i = 0; i < ng; i++)
grade[i] = g[i];
} else {
*this = Student();
}
}
void Student::display() const {
if (no > 0) {
cout << no << ":\n";
cout.setf(ios::fixed);
cout.precision(2);
for (int i = 0; i < ng; i++) {
cout.width(6);
cout << grade[i] << endl;
}
cout.unsetf(ios::fixed);
cout.precision(6);
} else {
cout << "no data available" << endl;
}
}
const Student& Student::operator+=(float g) {
if (no != 0 && ng < NG && g >= 0.f && g <= 100.f)
grade[ng++] = g;
return *this;
}
bool operator==(const Student& lhs, const Student& rhs) {
bool same = lhs.getStudentNo() == rhs.getStudentNo() &&
2021/8/8 Encapsulation | Helper Functions
https://ict.senecacollege.ca/~oop244/pages/content/nonme.html 6/9
lhs.getNoGrades() == rhs.getNoGrades();
for (int i = 0; i < lhs.getNoGrades() && same; i++)
same = lhs.getGrade(i) == rhs.getGrade(i);
return same;
}
Student operator+(const Student& student, float grade) {
Student copy = student; // makes a copy
copy += grade; // calls the += operator on copy
return copy; // return updated copy
}
Student operator+(float grade, const Student& student) {
return student + grade; // calls operator+(const
// Student&, float)
}
The following client code produces the results shown on the right:
// Helper Operator
// helper-addition-operator.cpp
#include
#include “Student.h”
using namespace std;
int main () {
float gh[] = {89.4f, 67.8f, 45.5f};
Student harry(1234, gh, 3);
harry = harry + 63.7f;
harry.display();
}
1234:
89.40
67.80
45.50
63.70
FRIENDSHIP
Friendship grants helper functions access to the private members of a class. By granting friendship status, a class lets a helper
function access to any of its private members: data members or member functions. Friendship minimizes class bloat.
To grant a helper function friendship status, we declare the function a friend and place its declaration inside the class definition. A
friendship declaration takes the form
friend Type identifier(type [, type, …]);
where Type is the return type of the function and identifier is the function’s name.
For example:
// Student.h
const int NG = 20;
class Student {
int no;
float grade[NG];
int ng;
public:
Student();
Student(int);
Student(int, const float*, int);
const Student& operator+=(float);
void display() const;
friend bool operator==(const Student&, const Student&);
};
Student operator+(const Student&, float);
Student operator+(float, const Student&);
Our implementation looks like:
2021/8/8 Encapsulation | Helper Functions
https://ict.senecacollege.ca/~oop244/pages/content/nonme.html 7/9
// Student.cpp
#include
using namespace std;
#include “Student.h”
Student::Student() {
no = 0;
ng = 0;
}
Student::Student(int n) {
float g[] = {0.0f};
*this = Student(n, g, 0);
}
Student::Student(int sn, const float* g, int ng_) {
bool valid = sn > 0 && g != nullptr && ng_ >= 0;
if (valid)
for (int i = 0; i < ng_ && valid; i++)
valid = g[i] >= 0.0f && g[i] <= 100.0f;
if (valid) {
// accept the client's data
no = sn;
ng = ng_ < NG ? ng_ : NG;
for (int i = 0; i < ng; i++)
grade[i] = g[i];
} else {
*this = Student();
}
}
void Student::display() const {
if (no > 0) {
cout << no << ":\n";
cout.setf(ios::fixed);
cout.precision(2);
for (int i = 0; i < ng; i++) {
cout.width(6);
cout << grade[i] << endl;
}
cout.unsetf(ios::fixed);
cout.precision(6);
} else {
cout << "no data available" << endl;
}
}
const Student& Student::operator+=(float g) {
if (no != 0 && ng < NG && g >= 0.f && g <= 100.f)
grade[ng++] = g;
return *this;
}
Student operator+(const Student& student, float grade) {
Student copy = student; // makes a copy
copy += grade; // calls the += operator on copy
return copy; // return updated copy
}
Student operator+(float grade, const Student& student) {
return student + grade; // calls operator+(const
// Student&, float)
}
bool operator==(const Student& lhs, const Student& rhs) {
bool same = lhs.no == rhs.no && lhs.ng == rhs.ng;
for (int i = 0; i < lhs.ng && same; i++)
same = lhs.grade[i] == rhs.grade[i];
return same;
}
2021/8/8 Encapsulation | Helper Functions
https://ict.senecacollege.ca/~oop244/pages/content/nonme.html 8/9
We have added the keyword friend to the declaration within the class definition. We do not apply the keyword to the function
definition.
The following client code compares the two objects:
// Friends
// friends.cpp
#include
#include “Student.h”
using namespace std;
int main () {
float gh[] = {89.4f, 67.8f, 45.5f};
Student harry(1234, gh, 3), harry_(1234, gh, 3);
harry_ += 63.7f;
if (harry == harry_)
cout << "are identical" << endl;
else
cout << "are different" << endl;
}
are different
The Cost of Friendship
A class definition that grants friendship to a helper function allows that function to alter the values of its private data members.
Granting friendship pierces encapsulation.
As a rule, we grant friendship judiciously only to helper functions that require both read and write access to the private data
members. Where read-only access is all that a helper function needs, using queries is probably more advisable.
Friendship is the strongest relationship that a class can grant an external entity.
Friendly Classes (Optional)
One class can grant another class access to its private members. A class friendship declaration takes the form
friend class Identifier;
where Identifier is the name of the class to which the host class grants friendship privileges.
For example, an Administrator class needs access to all information held within each Student object. To grant this access,
we simply include a class friendship declaration within the Student class definition
// Student.h
const int M = 13;
class Student {
int no;
char grade[M+1];
public:
Student();
Student(int);
Student(int, const char*);
void display() const;
const Student& operator+=(char);
friend bool areIdentical(const Student&, const Student&);
friend class Administrator;
};
No Reciprocity, Transitivity or Exclusivity (Optional)
Friendship is neither reciprocal, transitive nor exclusive. Just because one class is a friend of another class does not mean that the
latter is a friend of the former. Just because a class is a friend of another class and that other class is a friend of yet another class
does not mean that the latter class is a friend of either of them. A friend of one class may be a friend of any other class.
Consider three classes: a Student, an Administrator and an Auditor.
Let the Auditor be a friend of the Administrator and the Administrator be a friend of the Student
2021/8/8 Encapsulation | Helper Functions
https://ict.senecacollege.ca/~oop244/pages/content/nonme.html 9/9
Just because the Auditor is a friend of any Administrator and the Administrator is a friend of any Student,
the Administrator is not necessarily a friend of the Auditor and the Student is not necessarily a friend of the
Administrator (lack of reciprocity)
Just because the Auditor is a friend of any Administrator and the Administrator is a friend of any Student,
the Auditor is not necessarily a friend of any Student (lack of transitivity)
SUMMARY
a helper function is a global function that supports a class
a helper function refers to the class that it supports through its explicit parameter(s)
a helper operator is typically an operator that does not change the value of its operands
a friend function has direct access to the private members of the class that granted the function friendship
friendship is neither reciprocal, transitive, nor exclusive
free helper functions reduce coupling at the cost of bloating a class
friendly helper functions reduce bloating at the cost of piercing encapsulation
EXERCISES
Complete the Handout on Helper Operators.
Complete the Workshop on Expressions
print this page Top
Previous: Classes and Resources Next: Input and Output Operators
ICT Home Outline Timeline
Notes IPC Notes MySeneca Workshops Assignments Instructor
Designed by Chris Szalwinski Copying From This Site Last Modified: 05/20/2017 11:50
https://ict.senecacollege.ca/~oop244/pages/handouts/h9.html
https://ict.senecacollege.ca/~oop244/pages/workshops/w6.html
https://ict.senecacollege.ca/~oop244/pages/content/nonme_p.html
https://ict.senecacollege.ca/~oop244/pages/content/deepc.html
https://ict.senecacollege.ca/~oop244/pages/content/custo.html
https://ict.senecac.on.ca/
https://ict.senecacollege.ca/~oop244/index.html
http://www.senecacollege.ca/ssos/findwithoutsemester/oop244/sict
https://ict.senecacollege.ca/~oop244/pages/timeline.html
https://ict.senecacollege.ca/~oop244/pages/content/index.html
https://scs.senecac.on.ca/~ipc144/pages/content/index.html
https://my.senecacollege.ca/webapps/portal/frameset.jsp
https://ict.senecacollege.ca/~oop244/dynamic/workshops/index.html
https://ict.senecacollege.ca/~oop244/pages/assignments/index.html
https://ict.senecacollege.ca/~oop244/pages/instructors/index.html
https://ict.senecacollege.ca/~oop244/pages/copyright.html
http://creativecommons.org/licenses/by/2.5/ca/