CS计算机代考程序代写 compiler c++ 2021/8/8 Encapsulation | Construction and Destruction

2021/8/8 Encapsulation | Construction and Destruction

https://ict.senecacollege.ca/~oop244/pages/content/ctors.html 1/12

ICT Home Outline Timeline Notes IPC Notes MySeneca Workshops Assignments Instructor

Software
Development

OOP244

Part C – Encapsulation

Construction and Destruction

Describe some basic features of a class
Introduce constructors and destructors as essential to encapsulation

Overload constructors to enhance client communication

“A class is a cohesive package that … describes the rules by which objects behave; these objects are referred to as instances of
that class.” (Wikipedia, 2008)

Class Features | Constructor | Destructor | Arrays | Overloading | Summary | Exercise

Object-oriented languages encapsulate the state and logic of a type using a class. A class describes the structure of the data that its
objects hold and the rules under which its member functions access and change that data. The implementation of a well-
encapsulated class has all details hidden within itself. Client code communicates with the objects of the class solely through its
public member functions.

This chapter describes some basic features of classes and introduces the special member functions that initialize and tidy up
objects of a class. This chapter covers the order of memory allocation and deallocation during object construction and destruction
as well as overloading of the special function that initializes objects.

CLASS FEATURES

Instance of a Class

Each object or instance of a class occupies its own region of memory. The data for the object is stored in that region of memory.

A definition of an object takes the form

Type identifier;

Type is the name of the class. indentifier is the name of the object.

Consider the following class definition

const int NG = 20;

class Student {
int no;
float grade[NG];
int ng;
public:
void set(int, const float*, int);
void display() const;
};

To create an object of our Student class named harry, we write:

Student harry;

To create five objects of our Student class, we write:

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/ctors_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 | Construction and Destruction

https://ict.senecacollege.ca/~oop244/pages/content/ctors.html 2/12

Student a, b, c, d, e;

The compiler allocates five regions in static memory, each of which holds the data for one of the five objects. Each region stores
the values of three data members – no, the array grade and ng. The compiler stores the member function instructions separately
and only once for all objects of the class.

Instance Variables

We call the data members in the class definition the object’s instance variables. Instance variables may be of

fundamental type (int, double, char, etc.)
compound type

class type (struct or class)
pointer type (to instances of data types – fundamental or compound)
reference type (to instances of data types – fundamental or compound)

Logic

The member function instructions apply to all objects of the class and there is no need to allocate separate logic memory for each
object. At run-time each call to a member function on an object accesses the same code, but different instance variables – those of
the object on which the client code has called the member function.

Consider the following client code. This code calls the same member function (display()) on five different Student objects
and displays five different sets of information in the same format:

Student a, b, c, d, e;

// different data for each object – same logic

a.display(); // displays the data stored in a
cout << endl; b.display(); // displays the data stored in b cout << endl; c.display(); // displays the data stored in c cout << endl; d.display(); // displays the data stored in d cout << endl; e.display(); // displays the data stored in e cout << endl; The memory allocated for member function code is shown on the left. The memory allocated for the instance variables is shown on the right: Class Privacy C++ compilers apply privacy at the class level. Any member function can access any private member of its class, including any data member of any instance of its class. In other words, privacy is not implemented at the individual object level. In the following example, we refer to private data members of a Student object within a member function called on a different Student object: const int NG = 20; class Student { int no; float grade[NG]; int ng; 2021/8/8 Encapsulation | Construction and Destruction https://ict.senecacollege.ca/~oop244/pages/content/ctors.html 3/12 public: void copyFrom(const Student& src); void set(int, const float*, int); void display() const; }; // ... void Student::copyFrom(const Student& src) { no = src.no; // copy data from one object to another ng = src.ng; // copy data from one object to another for (int i = 0; i < NG; i++) grade[i] = src.grade[i]; // copy from one object to another } 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() { Student harry, backup; float grade[] = {78.9f, 67.5f, 45.5f, 64.35f}; harry.set(975, grade, 4); backup.copyFrom(harry); backup.display(); } 975: 78.90 67.50 45.50 64.35 The copyFrom(const Student& src) member function copies the values of the private data members of harry to the private data members of backup. CONSTRUCTOR Complete encapsulation requires a mechanism for initializing data members at creation-time. Without initialization at creation- time, an object's data members contain undefined values until client code calls a modifier that sets that data. Before any modifier call, client code can inadvertently 'break' the object by calling a member function that assumes valid data. For instance, client code could call display() before ever calling set(). The following code generates the spurious output on the right // Calling an Object with Uninitialized Data // uninitialized.cpp #include
using namespace std;
const int NG = 20;

class Student {
int no;
float grade[NG];
int ng;
public:
void set(int, const float*, int);
void display() const;
};

void Student::set(int sn, const float* g, int ng_) {
bool valid = sn > 0 && g != nullptr && ng_ >= 0;
if (valid)

2021/8/8 Encapsulation | Construction and Destruction

https://ict.senecacollege.ca/~oop244/pages/content/ctors.html 4/12

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 { no = 0; ng = 0; } } 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() { Student harry; harry.display(); float grade[] = {78.9f, 67.5f, 45.55f}; harry.set(975, grade, 3); harry.display(); } 12052848 975: 78.90 67.50 45.55 Initially harry's student number, grades and their number are undefined. If the value stored in ng is negative, the first call to display() outputs an unrecognizable student number and no grades. After the call to set(), the data values are defined and the subsequent call to display() produces recognizable results. To avoid undefined behavior or broken objects, we need to initialize each object to an empty state at creation-time. Definition The special member function that any object invokes at creation-time is called its class' constructor. We use the default constructor to execute any preliminary logic and set the object to an empty state. The default constructor takes its name from the class itself. The prototype for this no-argument constructor takes the form Type(); Type is the name of the class. Its declaration does not include a return type. Example To define a default constructor for our Student class, we declare its prototype explicitly in the class definition: const int NG = 20; class Student { int no; float grade[NG]; int ng; public: Student(); void set(int, const float*, int); void display() const; }; 2021/8/8 Encapsulation | Construction and Destruction https://ict.senecacollege.ca/~oop244/pages/content/ctors.html 5/12 We define the constructor in the implementation file: Student::Student() { no = 0; ng = 0; } Default Behavior If we don't declare a constructor in the class definition, the compiler inserts a default no-argument constructor with an empty body: Student::Student() { } Note that this default constructor leaves the instance variables uninitialized. Understanding Order Construction The compiler assembles an object in the following order 1. allocates memory for each instance variable in the order listed in the class definition 2. executes the logic, if any, within the constructor's definition Member Function Calls Since the constructor starts executing at instantiation, no normal member function is called before the constructor. Every normal member function is called after instantiation. Multiple Objects The compiler creates multiple objects defined in a single declaration in the order specified by the declaration. For example, the following code generates the output on the right // Constructors // constructors.cpp #include
#include
using namespace std;
const int NG = 20;

class Student {
int no;
float grade[NG];
int ng;
public:
Student();
void set(int, const float*, int);
void display() const;
};

// initializes the data members
//
Student::Student() {
cout << "In constructor" << endl; no = 0; ng = 0; } void Student::set(int sn, const float* g, int ng_) { 2021/8/8 Encapsulation | Construction and Destruction https://ict.senecacollege.ca/~oop244/pages/content/ctors.html 6/12 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 { no = 0; ng = 0; } } 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 () { Student harry, josee; float gh[] = {89.4f, 67.8f, 45.5f}; float gj[] = {83.4f, 77.8f, 55.5f}; harry.set(1234, gh, 3); josee.set(1235, gj, 3); harry.display(); josee.display(); } In constructor In constructor 1234: 89.40 67.80 45.50 1235: 83.40 77.80 55.50 The compiler assembles harry and calls its constructor first and assembles josee and calls its constructor afterwards. Safe Empty State Initializing an object's instance variables in a constructor ensures that the object has a well-defined state from the time of its creation. In the above example, we say that harry and josee are in safe empty states until the set() member function changes those states. If client code calls member functions on objects in safe empty states, the objects do not break and behave as expected. For example, the following client code produced the no data available message listed on the right: // Safe Empty State // safeEmpty.cpp #include
using namespace std;

int main ( ) {
Student harry, josee;

harry.display();
josee.display();
float gh[] = {89.4f, 67.8f, 45.5f};
float gj[] = {83.4f, 77.8f, 55.5f};
harry.set(1234, gh, 3);
josee.set(1235, gj, 3);
harry.display();
josee.display();
}

In constructor
In constructor
no data available
no data available
1234:
89.40
67.80
45.50
1235:
83.40
77.80
55.50

2021/8/8 Encapsulation | Construction and Destruction

https://ict.senecacollege.ca/~oop244/pages/content/ctors.html 7/12

The safe empty state is identical for all objects of the same class.

DESTRUCTOR

Complete encapsulation also requires a mechanism for tidying up at the end of an object’s lifetime. An object with dynamically
allocated memory needs to deallocate that memory before going out of scope. An object that has written data to a file needs to
flush the file’s buffer and close the file before going out of scope.

Definition

The special member function that every object invokes before going out of scope is called its class’ destructor. We code all of the
terminal logic in this special member function.

The destructor takes its name from the class itself, prefixing it with the tilde symbol (~). The prototype for a destructor takes the
form

~Type();

Type is the name of the class. Destructors have no parameters or return values.

An object’s destructor

is called automatically
cannot be overloaded
should not be called explicitly

Example

To define the destructor for our Student class, we declare its prototype in the class definition:

const int NG = 20;

class Student {
int no;
float grade[NG];
int ng;
public:
Student();
~Student();
void set(int, const float*, int);
void display() const;
};

We define the member function in the implementation file:

Student::~Student() {
// insert our terminal code here
}

Default Behavior

If we don’t declare a destructor in the class definition, the compiler inserts a destructor with an empty body:

Student::~Student() {
}

Understanding Order

Member Function Calls

An object’s destructor starts executing only after every normal member function has completed its execution.

2021/8/8 Encapsulation | Construction and Destruction

https://ict.senecacollege.ca/~oop244/pages/content/ctors.html 8/12

Client code cannot call any member function on an object after the object has called its destructor and gone out of scope.

Destruction

Object destruction proceeds in the following order

1. execute the logic of the object’s destructor
2. deallocate memory for each instance variable in opposite order to that listed in the class definition

Multiple Objects

The compiler destroys sets of objects in opposite order to that of their creation.

For example, the following code generates the output on the right:

// Constructors and Destructors
// destructors.cpp

#include
#include
using namespace std;
const int NG = 20;

class Student {
int no;
float grade[NG];
int ng;
public:
Student();
~Student();
void set(int, const float*, int);
void display() const;
};

Student::Student() {
cout << "In constructor" << endl; no = 0; ng = 0; } // executed before object goes out of scope // Student::~Student() { cout << "In destructor for " << no << endl; } void Student::set(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 { no = 0; ng = 0; } } void Student::display() const { if (no > 0) {
cout << no << ":\n"; 2021/8/8 Encapsulation | Construction and Destruction https://ict.senecacollege.ca/~oop244/pages/content/ctors.html 9/12 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 () { Student harry, josee; float gh[] = {89.4f, 67.8f, 45.5f}; float gj[] = {83.4f, 77.8f, 55.5f}; harry.set(1234, gh, 3); josee.set(1235, gj, 3); harry.display(); josee.display(); } In constructor In constructor 1234: 89.40 67.80 45.50 1235: 83.40 77.80 55.50 In destructor for 1235 In destructor for 1234 The compiler destroys josee first followed by harry. CONSTRUCTION AND DESTRUCTION OF ARRAYS The order of construction and destruction of elements of an array of objects follows the order described above. The compiler creates the elements of an array one at a time sequentially starting from the first element and ending with the last. Each object calls the default constructor at creation-time. When the array goes out of scope, the last element calls its destructor first and the first element calls its destructor last. For example, the following code generates the output on the right: // Constructors, Destructors and Arrays // ctorsDtorsArrays.cpp #include
#include
using namespace std;
const int NG = 20;

class Student {
int no;
float grade[NG];
int ng;
public:
Student();
~Student();
void set(int, const float*, int);
void display() const;
};

Student::Student() {
cout << "In constructor" << endl; no = 0; ng = 0; } Student::~Student() { cout << "In destructor for " << no << endl; } void Student::set(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; 2021/8/8 Encapsulation | Construction and Destruction https://ict.senecacollege.ca/~oop244/pages/content/ctors.html 10/12 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 { no = 0; ng = 0; } } 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 () { Student a[3]; float g0[] = {89.4f, 67.8f, 45.5f}; float g1[] = {83.4f, 77.8f, 55.5f}; float g2[] = {77.8f, 83.4f, 55.5f}; a[0].set(1234, g0, 3); a[1].set(1235, g1, 3); a[2].set(1236, g2, 3); for (int i = 0; i < 3; i++) a[i].display(); } In constructor In constructor In constructor 1234: 89.40 67.80 45.50 1235: 83.40 77.80 55.50 1236: 77.80 83.40 55.50 In destructor for 1236 In destructor for 1235 In destructor for 1234 The destructor for element a[2] executes before the destructor for a[1], which executes before the destructor for a[0]. The order of destruction is based on order of construction and not on order of usage. OVERLOADING CONSTRUCTORS Overloading a class' constructor adds communication options for client code. Client code can select the most appropriate set of arguments at creation time. For example, to let client code initialize a Student object with a student number and a set of grades, let us define a three- argument constructor similar to our set() function: // Overloaded Constructor // overload.cpp #include
using namespace std;
const int NG = 20;

class Student {
int no;
float grade[NG];
int ng;
public:
Student();
Student(int, const float*, int);
~Student();
void set(int, const float*, int);
void display() const;
};

2021/8/8 Encapsulation | Construction and Destruction

https://ict.senecacollege.ca/~oop244/pages/content/ctors.html 11/12

Student::Student() {
cout << "In constructor" << endl; no = 0; ng = 0; } Student::Student(int sn, const float* g, int ng_) { cout << "In 3-arg constructor" << endl; set(sn, g, ng_); } Student::~Student() { cout << "In destructor for " << no << endl; } void Student::set(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 { no = 0; ng = 0; } } 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}; float gj[] = {83.4f, 77.8f, 55.5f}; Student harry(1234, gh, 3), josee(1235, gj, 3); harry.display(); josee.display(); } In 3-arg constructor In 3-arg constructor 1234: 89.40 67.80 45.50 1235: 83.40 77.80 55.50 In destructor for 1235 In destructor for 1234 This new constructor includes the validation logic by calling set(). The compiler calls only one constructor at creation-time. In this example, the compiler does not call the default constructor. No-argument constructor is not always implemented If the class definition includes the prototype for a constructor with some parameters but does not include the prototype for a no- argument default constructor, the compiler DOES NOT insert an empty-body, no-argument default constructor. The compiler only inserts an empty-body, no-argument default constructor if the class definition does not declare ANY constructor. If we define a constructor with some parameters, we typically also define a no-argument default constructor. This is important in the creation of arrays of objects. The creation of each element in the array requires a no-argument default constructor. 2021/8/8 Encapsulation | Construction and Destruction https://ict.senecacollege.ca/~oop244/pages/content/ctors.html 12/12 SUMMARY we refer to the data members of an object as its instance variables privacy operates at the class level, not at the object level the constructor is a special member function that an object invokes at creation time the name of the constructor is the name of the class the destructor is a special member function that an object invokes at destruction time the name of the destructor is the name of the class prefixed by a ~ the constructor and destructor do not have return types the compiler inserts an empty body constructor/destructor into any class definition that does not declare a constructor/destructor the compiler does not insert an empty-body, no-argument constructor into a class definition that declares any form of constructor EXERCISES Complete the Handout on Constructors and Destructors Complete the Workshop on Constructors print this page Top Previous: Dynamic Memory Next: The Current Object ICT Home Outline Timeline Notes IPC Notes MySeneca Workshops Assignments Instructor Designed by Chris Szalwinski Copying From This Site Last Modified: 02/06/2018 13:06 https://ict.senecacollege.ca/~oop244/pages/handouts/h5.html https://ict.senecacollege.ca/~oop244/dynamic/workshops/w4.html https://ict.senecacollege.ca/~oop244/pages/content/ctors_p.html https://ict.senecacollege.ca/~oop244/pages/content/dynam.html https://ict.senecacollege.ca/~oop244/pages/content/membe.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/