2021/8/8 Encapsulation | Classes and Resources
https://ict.senecacollege.ca/~oop244/pages/content/deepc.html 1/8
ICT Home Outline Timeline Notes IPC Notes MySeneca Workshops Assignments Instructor
Software
Development
OOP244
Part C – Encapsulation
Classes and Resources
Design classes with dynamically allocated resources to model the components of a programming solution
Define the copy constructor and assignment operator for a class with a resource
“Never allocate more than one resource in a single statement” (Sutter, Alexandrescu, 2005)
Resource Pointers | Deep Copies and Assignments | Copy Constructor
Assignment Operator | Localization | Copies Prohibited | Summary | Exercise
In object-oriented programming, we design classes to behave independently of their client applications. Wherever client code
dictates the amount of memory that an object requires, the memory that needs to be allocated is unknown at compile-time. Only
once the client has instantiated the object will the object know how much memory the client requires. To review run-time memory
allocation and deallocation see the chapter entitled Dynamic Memory.
Memory that an object allocates at run-time represents a resource to its class. Management of this resource requires additional
logic that was unnecessary in simpler designs. This additional logic ensures proper handling of the resource and is often called
deep copying and deep assignment.
This chapter describes how to implement deep copying and deep assignment logic. The member functions that manage resources
are the constructors, the assignment operator and the destructor.
RESOURCE INSTANCE POINTERS
A C++ object refers to a resource through a resource instance pointer. This pointer holds the address of the resource. The address
lies outside the object’s static memory.
Case Study
Let us upgrade our Student class to accommodate a variable number of grades. The client code specifies the number at run-
time. The array of grades is now a dynamically allocated resource. We allocate
static memory for the resource instance variable (grade)
dynamic memory for the grade array itself
In this section, we focus on the constructors and the destructor for our Student class. Let us assume that the client does not
copy or assign objects of this class. We shall cover the copying and assignment logic in subsequent sections:
// Resources – Constructor and Destructor
// resources.cpp
#include
using namespace std;
class Student {
int no;
float* grade;
int ng;
public:
Student();
Student(int);
Student(int, const float*, int);
~Student();
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/deepc_p.html
https://ict.senecacollege.ca/~oop244/pages/content/dynam.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 | Classes and Resources
https://ict.senecacollege.ca/~oop244/pages/content/deepc.html 2/8
void display() const;
};
Student::Student() {
no = 0;
ng = 0;
grade = nullptr;
}
Student::Student(int sn) {
float g[] = {0.0f};
grade = nullptr;
*this = Student(sn, 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_;
// allocate dynamic memory
if (ng > 0) {
grade = new float[ng];
for (int i = 0; i < ng; i++)
grade[i] = g[i];
} else {
grade = nullptr;
}
} else {
grade = nullptr;
*this = Student();
}
}
Student::~Student() {
delete [] grade;
}
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;
}
}
int main () {
float gh[] = {89.4f, 67.8f, 45.5f};
Student harry(1234, gh, 3);
harry.display();
}
1234:
89.40
67.80
45.50
The no-argument constructor places the object in a safe empty state. The three-argument constructor allocates dynamic memory
for the resource only if the data received is valid. The pre-initialization of grade is a precaution that ensures no inadvertent
destruction of memory (see the assignment operator section below). The destructor deallocates any memory that the constructor
allocated. Deallocating memory at the nullptr address has no effect.
DEEP COPIES AND ASSIGNMENTS
2021/8/8 Encapsulation | Classes and Resources
https://ict.senecacollege.ca/~oop244/pages/content/deepc.html 3/8
In designing a class with a resource, we expect the resource associated with one object to be independent of the resource
associated with another object. That is, if we change the resource data in one object, we expect the resource data in the other
object to remain unchanged. In copying and assigning objects we ensure resource independence through deep copying and deep
assigning. Deep copying and deep assigning involve copying the resource data. Shallow copying and assigning involve copying
the instance variables only and are only appropriate for non-resource instance variables.
Implementing deep copying and assigning requires dynamic allocation and deallocation of memory. The copying process includes
not only the non-resource instance variables but also the resource data itself.
In each deep copy, we allocate memory for the underlying resource and copy the contents of the source resource into the
destination memory. We shallow copy the instance variables that are NOT resource instance variables. For example, in our
Student class, we shallow copy the student number and number of grades, but not the address stored in the grade pointer.
Two special member functions manage allocations and deallocations associated with deep copying and deep copy assigning:
the copy constructor
the copy assignment operator
If we do not declare a copy constructor, the compiler inserts code that implements a shallow copy. If we do not declare a copy
assignment operator, the compiler inserts code that implements a shallow assignment.
COPY CONSTRUCTOR
The copy constructor contains the logic for copying from a source object to a newly created object of the same type. The compiler
calls this constructor when the client code
1. creates an object by initializing it to an existing object
2. copies an object by value in a function call
3. returns an object by value from a function
Declaration
The declaration of a copy constructor takes the form
Type(const Type&);
where Type is the name of the class.
To define a copy constructor, we insert its declaration into the class. For example, we insert the following into the definition of
our Student class:
// Student.h
class Student {
int no;
float* grade;
int ng;
public:
Student();
Student(int, const char*);
Student(const Student&);
~Student();
void display() const;
};
Definition
The definition of a copy constructor contains logic to
1. perform a shallow copy on all non-resource instance variables
2021/8/8 Encapsulation | Classes and Resources
https://ict.senecacollege.ca/~oop244/pages/content/deepc.html 4/8
2. allocate memory for each new resource
3. copy data from the source resource to the newly created resource
For example, the following code implements a deep copy on objects of our Student class:
// Student.cpp
#include
using namespace std;
#include “Student.h”
// …
Student::Student(const Student& src) {
// shallow copies
no = src.no;
ng = src.ng;
// allocate dynamic memory for grades
if (src.grade != nullptr) {
grade = new float[ng];
// copy data from the source resource
// to the newly allocated resource
for (int i = 0; i < ng; i++)
grade[i] = src.grade[i];
}
else {
grade = nullptr;
}
}
Since the source data was validated on its original receipt from the client code and privacy constraints have ensured that this data
has not been corrupted in the interim, we do not need to revalidate the data in the copy constructor logic.
COPY ASSIGNMENT OPERATOR
The copy assignment operator contains the logic for copying data from an existing object to an existing object. The compiler calls
this member operator whenever for client code expressions of the form
identifier = identifier
identifier refers to the name of an object.
Declaration
The declaration of an assignment operator takes the form
Type& operator=(const Type&);
the left Type is the return type and the right Type is the type of the source operand.
To define the copy assignment operator, we insert its declaration into the class definition. For example, we insert the following
declaration into the definition of our Student class:
// Student.h
class Student {
int no;
float* grade;
int ng;
public:
Student();
Student(int, const float*, int);
Student(const Student&);
Student& operator=(const Student&);
~Student();
void display() const;
};
2021/8/8 Encapsulation | Classes and Resources
https://ict.senecacollege.ca/~oop244/pages/content/deepc.html 5/8
Definition
The definition of the copy assignment operator contains logic to:
1. check for self-assignment
2. shallow copy the non-resource instance variables to destination variables
3. deallocate any previously allocated memory for the resource associated with the current object
4. allocate a new memory for the resource associated with the current object
5. copy resource data from the source object to the newly allocated memory of the current object
For example, the following code performs a deep copy assignment on objects of our Student class:
// Student.cpp
// ...
Student& Student::operator=(const Student& source) {
// check for self-assignment
if (this != &source) {
// shallow copy non-resource variables
no = source.no;
ng = source.ng;
// deallocate previously allocated dynamic memory
delete [] grade;
// allocate new dynamic memory, if needed
if (source.grade != nullptr) {
grade = new float[ng];
// copy the resource data
for (int i = 0; i < ng; i++)
grade[i] = source.grade[i];
}
else {
grade = nullptr;
}
}
return *this;
}
To trap a self-assignment from the client code (a = a), we compare the address of the current object to the address of the source
object. If the addresses match, we skip the assignment logic altogether. If we neglect to check for self-assignment, the
deallocation statement would release the memory holding the resource data and we would lose access to the source resource
resulting in our logic failing at grade[i] = source.grade[i].
LOCALIZATION
The code in our definition of the copy constructor is identical to most of the code in our definition of the assignment operator. To
avoid such duplication and thereby improve maintainability we can localize the logic in a:
private member function - localize the common code in a private member function and call that member function from
both the copy constructor and the copy assignment operator
direct call - call the assignment operator directly from the copy constructor
Private Member Function
The following solution localizes the common code in a private member function named init() and calls this function from the
copy constructor and the copy assignment operator:
void Student::init(const Student& source) {
no = source.no;
ng = source.ng;
if (source.grade != nullptr) {
grade = new float[ng];
for (int i = 0; i < ng; i++)
grade[i] = source.grade[i];
}
else {
2021/8/8 Encapsulation | Classes and Resources
https://ict.senecacollege.ca/~oop244/pages/content/deepc.html 6/8
grade = nullptr;
}
}
Student::Student(const Student& source) {
init(source);
}
Student& Student::operator=(const Student& source) {
if (this != &source) { // check for self-assignment
// deallocate previously allocated dynamic memory
delete [] grade;
init(source);
}
return *this;
}
Direct Call
The following solution initializes the resource instance variable in the copy constructor to nullptr and calls the copy
assignment operator directly:
Student::Student(const Student& source) {
grade = nullptr;
*this = source; // calls assignment operator
}
Student& Student::operator=(const Student& source) {
if (this != &source) { // check for self-assignment
no = source.no;
ng = source.ng;
// deallocate previously allocated dynamic memory
delete [] grade;
// allocate new dynamic memory
if (source.grade != nullptr) {
grade = new float[ng];
// copy resource data
for (int = 0; i < ng; i++)
grade[i] = source.grade[i];
}
else {
grade = nullptr;
}
}
return *this;
}
Assigning grade to nullptr in the copy constructor ensures that the assignment operator does not deallocate any memory if
called by the copy constructor.
Assigning Temporary Objects
Assigning a temporary object to the current object requires additional code if the object manages resources. To prevent the
assignment operator from releasing not-as-yet-acquired resources we initialize each resource instance variable to an empty value
(nullptr).
For example, in the constructors for our Student object, we add the highlighted code:
class Student {
int no;
float* grade;
int ng;
public:
// ...
};
Student::Student() {
no = 0;
ng = 0;
grade = nullptr;
2021/8/8 Encapsulation | Classes and Resources
https://ict.senecacollege.ca/~oop244/pages/content/deepc.html 7/8
}
Student::Student(int n) {
float g[] = {0.0f};
grade = nullptr;
*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_;
// allocate dynamic memory
if (ng > 0) {
grade = new float[ng];
for (int i = 0; i < ng; i++)
grade[i] = g[i];
} else {
grade = nullptr;
}
} else {
grade = nullptr;
*this = Student();
}
}
COPIES PROHIBITED
Certain class designs require prohibiting client code from copying or copy assigning any instance of a class. To prohibit copying
and/or copy assigning, we declare the copy constructor and/or the copy assignment operator as deleted members of our class:
class Student {
int no;
float* grade;
int ng;
public:
Student();
Student(int, const float*, int);
Student(const Student& source) = delete;
Student& operator=(const Student& source) = delete;
~Student();
void display() const;
};
The keyword delete used in this context has no relation to deallocating dynamic memory.
SUMMARY
a class with resources requires custom definitions of a copy constructor, copy assignment operator and destructor
the copy constructor copies data from an existing object to a newly created object
the copy assignment operator copies data from an existing object to an existing object
initialization, pass by value, and return by value client code invokes the copy constructor
the copy constructor and copy assignment operator should shallow copy only the non-resource instance variables
the copy assignment operator should check for self-assignment
EXERCISES
Complete the Handout on Class with a Resource
Complete the Workshop on Class with a Resource
https://ict.senecacollege.ca/~oop244/pages/handouts/h7.html
https://ict.senecacollege.ca/~oop244/pages/workshops/w5.html
2021/8/8 Encapsulation | Classes and Resources
https://ict.senecacollege.ca/~oop244/pages/content/deepc.html 8/8
print this page Top
Previous: Member Operators Next: Helper Functions
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/content/deepc_p.html
https://ict.senecacollege.ca/~oop244/pages/content/overl.html
https://ict.senecacollege.ca/~oop244/pages/content/nonme.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/