CS计算机代考程序代写 flex c++ 2021/8/8 Encapsulation | Input and Output Operators

2021/8/8 Encapsulation | Input and Output Operators

https://ict.senecacollege.ca/~oop244/pages/content/custo.html 1/11

ICT Home Outline Timeline Notes IPC Notes MySeneca Workshops Assignments Instructor

Software
Development

OOP244

Part C – Encapsulation

Input and Output Operators

Use stream objects to interact with users and access persistent data
Introduce association relationships between classes

Overload the extraction and insertion operators as helper operators

“You don’t need to modify istream or ostream to add new << and >> operators” (Stroustrup, 1997)

Stream Library | Standard I/O Operators | File I/O Operators | String Class | Summary | Exercises

The relationships between classes that object-oriented languages support include compositions and associations. Both of these
relationships are more loosely coupled than friendship. A composition is a relationship in which one class has another class, while
an association is a relationship in which one class uses another class. In relationship diagrams, associations appear as open circles
and compositions as filled circles. The diagram below shows that Code uses the Calendar (to determine availability), while
each Course has a Course Code class.

Associations are more loosely coupled than compositions. Typical examples of associations are relationships between the stream-
based input and output library classes that support the C++ language and our own custom classes. To create these relationships,
we overload the insertion and extraction operators as helper operators that take stream objects as their left operands and objects of
our class type as their right operands.

This chapter describes the stream-based input/output library and shows how to overload the insertion and extraction operators for
objects of our custom classes. This chapter shows how to define file objects and use them to store and retrieve variables of
fundamental type. The chapter concludes by introducing the standard library’s string class, which manages character stream
input of user-defined length.

STREAM LIBRARY OVERVIEW

The stream-based input/output library that supports the core C++ language overloads two operators for extracting values from an
input stream and inserting values into an output stream:

>> (extract from an input stream)
<< (insert into an output stream) The library embeds its class definitions in the standard namespace (std). To access those instances of these classes that the library predefines, we prefix their identifiers with the namespace identifier and the scope resolution operator (std::). For example, #include

int main() {
int x;

std::cout << "Enter an integer : "; std::cin >> x;
std::cout << "You entered " << x << std::endl; } Enter an integer : 3 You entered 3 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/custo_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 | Input and Output Operators https://ict.senecacollege.ca/~oop244/pages/content/custo.html 2/11 Standard I/O and File I/O Standard I/O The iostream system header file contains the definitions for streaming from and to standard devices. #include

This header file includes the definitions of the

std::istream class – for processing input from the standard input device
std::ostream class – for processing output to the standard output devices

This header file also predefines the standard input and output objects:

std::istream
std::cin – standard input

std::ostream
std::cout – standard output
std::cerr – standard error
std::clog – standard log

We use these objects directly and don’t need to redefine them.

File I/O

The fstream system header file contains the definitions for streaming from and to files.

#include

This header file includes the definitions of the

std::ifstream class – for processing input from a file stream
std::ofstream class – processing output to a file stream
std::fstream class – processing input from and output to a file stream

These three classes manage communication between file streams containing 8-bit characters and system memory. They provide
access to a file stream through separate input and output buffers.

Design Considerations

In overloading the insertion and extraction operators for our class types, good design suggests:

providing flexibility in the selection of stream objects
resolving scope on classes and objects defined in header files
enabling cascading as implemented for fundamental types

Selection of Stream Objects

To enable selection of the stream objects by the client code, we upgrade our display() member function to receive a
modifiable reference to an object of std::ostream type. The changes to the header file are shown on the left and the
implementation file on the right:

// Student.h

#include // for
// std::ostream
const int NG = 20;

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

// Student.cpp

#include
#include “Student.h”
using namespace std;

// …

void Student::display(ostream&
os) const {
if (no > 0) {
os << no << ":\n"; os.setf(ios::fixed); os.precision(2); 2021/8/8 Encapsulation | Input and Output Operators https://ict.senecacollege.ca/~oop244/pages/content/custo.html 3/11 void display(std::ostream&) const; }; for (int i = 0; i < ng; i++) { os.width(6); os << grade[i] << endl; } os.unsetf(ios::fixed); os.precision(6); } else { os << "no data available" << endl; } } With this upgrade the client code can choose the destination stream (cout, cerr, or clog). Header Files A header files may be included alongside other header files written by other developers. To avoid conflicts between the header files included in an implementation file, we follow certain guidelines: include system header files before custom header files insert namespace directives after all header files resolve the scope of any identifier in a header file at the identifier itself The preferred method of coding header files is shown on the right: // Student.h #include
using namespace std; // POOR DESIGN
const int NG = 20;

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

// Student.h

#include // GOOD DESIGN
const int NG = 20;

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

Exposing all of the names in any namespace as on the left may lead to unnecessary conflicts with new names or conflicts when
several header files are included in an implementation file. Resolving scope in the display() function’s parameter list
identifies the class used with its namespace, without exposing any name in that namespace.

Cascading

The following expression is a cascaded expression

std::cout << x << y << z << std::endl; Cascading support enables concatenation of operations where the leftmost operand serves as the left operand for every operation in a compound expression. The cascaded expression above expands to two simpler sub-expressions executed in the following order: std::cout << x; std::cout << y << z << std::endl; The cascaded sub-expression std::cout << y << z << std::endl; expands to two simpler sub-expressions executed in the following order: 2021/8/8 Encapsulation | Input and Output Operators https://ict.senecacollege.ca/~oop244/pages/content/custo.html 4/11 std::cout << y; std::cout << z << std::endl; Finally, the cascaded sub-expression std::cout << z << std::endl; expands into two simpler sub-expressions executed in the following order: std::cout << z; std::cout << std::endl; Enabling cascading requires that we return a modifiable reference to the left operand. Returning a modifiable reference from a function lets the client code use the return value as the left operand for the operator on its right. STANDARD I/O OPERATORS The prototypes for the overloaded insertion and extraction operators for standard input and output on objects of our own classes take the form std::istream& operator>>(std::istream&, Type&);
std::ostream& operator<<(std::ostream&, const Type&); where Type is the name of the class. The header file for our Student class that includes their declarations is: // Student.h #include // for std::ostream, std::istream
const int NG = 20;

class Student {
int no;
float grade[NG];
int ng;
public:
Student();
Student(int);
Student(int, const float*, int);
void read(std::istream&);
void display(std::ostream& os) const;
};

std::istream& operator>>(std::istream& is, Student& s);
std::ostream& operator<<(std::ostream& os, const Student& s); The implementation file for our upgraded Student class contains: // Student.cpp #include "Student.h" using namespace std; Student::Student() { no = 0; ng = 0; } Student::Student(int n) { *this = Student(n, nullptr, 0); } 2021/8/8 Encapsulation | Input and Output Operators https://ict.senecacollege.ca/~oop244/pages/content/custo.html 5/11 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::read(istream& is) { int no; // will hold the student number int ng; // will hold the number of grades float grade[NG]; // will hold the grades cout << "Student Number : "; is >> no;
cout << "Number of Grades : "; is >> ng;
if (ng > NG) ng = NG;
for (int i = 0; i < ng; i++) { cout << "Grade " << i + 1 << " : "; is >> grade[i];
}

// construct a temporary Student
Student temp(no, grade, ng);
// if data is valid, the temporary object into the current object
if (temp.no != 0)
*this = temp;
}

void Student::display(ostream& os) const {
if (no > 0) {
os << no << ":\n"; os.setf(ios::fixed); os.precision(2); for (int i = 0; i < ng; i++) { os.width(6); os << grade[i] << endl; } os.unsetf(ios::fixed); os.precision(6); } else { os << "no data available" << endl; } } std::ostream& operator<<(ostream& os, const Student& s) { s.display(os); return os; } std::istream& operator>>(istream& is, Student& s) {
s.read(is);
return is;
}

The following client code uses our upgraded Student class accepts the input shown on the right and produces the results shown
below:

// Standard I/O Operators
// standardIO.cpp

#include “Student.h” Student Number : 1234

2021/8/8 Encapsulation | Input and Output Operators

https://ict.senecacollege.ca/~oop244/pages/content/custo.html 6/11

int main () {
Student harry;

std::cin >> harry;
std::cout << harry; } Number of Grades : 2 Grade 1 : 56.7 Grade 2 : 78.9 1234: 56.70 78.90 FILE I/O OPERATORS The stream library does not predefine any file objects as instances of the file stream classes. To create file objects, we need to define them ourselves and connect them to a named file. A file object is an instance of one of the file stream classes. When used with the insertion or extraction operators on a connected file, a file object streams the data in formatted form. File Connections We can connect a file object to a file for reading, writing or both. The object's destructor closes the connection. Input File Objects To create a file object for reading we define an instance of the std::ifstream class. This class includes a no-argument constructor as well as one that receives the address of a C-style null-terminated string containing the file name. For example, // Create a File for Reading // createFileReading.cpp #include

int main() {
std::ifstream f(“input.txt”); // connects fin to input.txt for reading
// …
}

To connect a file to an existing file object, we call the open() member function on the object.

For example,

// Connect to a File for Reading
// connectFileReading.cpp

#include

int main() {
std::ifstream fin; // defines a file object named fin
fin.open(“input.txt”); // connects input.txt to fin
// …
}

Output File Objects

To create a file object for writing we define an instance of the std::ofstream class. This class includes a no-argument
constructor as well as one that receives the address of a C-style null-terminated string containing the name of the file.

For example,

// Writing to a File
// writeFile.cpp

#include

int main() {
std::ofstream fout(“output.txt”); // connects fout to output.txt for writing
// …
}

2021/8/8 Encapsulation | Input and Output Operators

https://ict.senecacollege.ca/~oop244/pages/content/custo.html 7/11

To connect a file to an existing file object, we call the open() member function on the object.

For example,

// Connect to a File for Writing
// connectFileWriting.cpp

#include

int main() {
std::ofstream fout; // create a file object named fout
std::ofstream fout(“output.txt”); // connects fout to output.txt for writing
// …
}

Confirming a File Connection

The is_open() member function called on a file object returns the current state of the object’s connection to a file:

#include
#include

std::ofstream fout(“output.txt”); // connects output.txt to fout for output

if (!fout.is_open()) {
std::cerr << "File is not open" << std::endl; } else { // file is open // ... } Streaming Fundamental Types The standard input/output library overloads the extraction and insertion operators for each fundamental type for the file stream classes with a file objects as left operands. Reading From a File A file object reads from a file under format control using the extraction operator in the same way as the standard input object (cin) reads using the extraction operator. Consider a file with a single record: 12 34 45 abc The output from the following program is shown on the right: // Reading a File // readFile.cpp #include
#include

int main() {
int i;

std::ifstream f(“input.txt”);
if (f.is_open()) {
while (f) {
f >> i;
if (f)
std::cout << i << ' '; else std::cout << "\n**Bad input**\n"; } } } 12 34 45 **Bad input** The file stream class definition overload the bool conversion operator to return false if the object is not ready for further streaming. A stream object is not ready for further streaming if it has encountered an error and has not been cleared. the topic of error states and clearing errors is covered later in the chapter entitled Input and Output Refinements. https://ict.senecacollege.ca/~oop244/pages/content/basic.html#sta 2021/8/8 Encapsulation | Input and Output Operators https://ict.senecacollege.ca/~oop244/pages/content/custo.html 8/11 Writing to a File A file object writes to a file under format control using the insertion operator in the same way as the standard output objects (cout, cerr and clog) write using the insertion operator. For example, the contents of the file created by the following program are shown on the right // Writing to a File // writeFile.cpp #include
#include

int main() {
int i;

std::ofstream f(“output.txt”);
if (f.is_open()) {
f << "Line 1" << std::endl; // record 1 f << "Line 2" << std::endl; // record 2 f << "Line 3" << std::endl; // record 3 } } Line 1 Line 2 Line 3 STRING CLASS (OPTIONAL) The examples in these notes have been limited to input data that fits within pre-allocated memory. In the case of character string input, the user determines the number of characters to enter and pre-allocation of the required memory is not possible. A user entering more characters than allocated memory can accept may cause a stream failure. The Problem Consider the user inputting a comment on a student's transcript. Since we only know how much memory to allocate for the comment after receiving the complete text, we cannot allocate that memory at compile-time or run-time before accepting the comment. The Solution The standard library's string class allocates the required amount of memory dynamically during the input process itself. A std::string object can accept as many characters as the user enters. The helper function std::getline() extracts the characters from the input stream. The prototype for this helper function is std::istream& getline(std::istream&, std::string&, char); The first parameter receives a modifiable reference to the std::istream object, the second parameter receives a modifiable reference to the std::string object and the third parameter receives the character delimiter for terminating extraction (newline by default). The header file contains the class definition with this prototype. The class definition includes two member functions
for converting its internal data into a C-style null-terminated string:

std::string::length() – returns the number of characters in the string
std::string::c_str() – returns the address of the C-style null-terminated version of the string

C-Style Example

The following client code extracts an unknown number of characters from the standard input stream, stores them in a C-style null-
terminated string and displays the character string on the standard output object in five steps:

1. define a string object to accept the input
2. extract the input using the std::getline() helper function
3. query the string object for the memory required
4. allocate dynamic memory for the requisite C-style null-terminated string
5. copy the data from the string object to the allocated memory
6. deallocate the allocated memory

// String Class example

2021/8/8 Encapsulation | Input and Output Operators

https://ict.senecacollege.ca/~oop244/pages/content/custo.html 9/11

// string.cpp

#include
#include

int main( ) {
char* s;
std::string str;

std::cout << "Enter a string : "; if (std::getline(std::cin, str)) { s = new char [str.length() + 1]; std::strcpy(s, str.c_str()); std::cout << "The string entered is : >” << s << '<' << std::endl; delete [] s; } } Student Class Example Let us upgrade our Student class to store a comment using a string object as a data member. The header file for our Student class contains: // Student.h #include
#include

const int NG = 20;

class Student {
int no;
float grade[NG];
int ng;
std::string comment;
public:
Student();
Student(int);
Student(int, const float*, int, const std::string&);
void read(std::istream&);
void display(std::ostream&) const;
};

std::istream& operator>>(std::istream& is, Student& s);
std::ostream& operator<<(std::ostream& os, const Student& s); The implementation file contains: // Student.cpp #include "Student.h" using namespace std; Student::Student() { no = 0; ng = 0; } Student::Student(int n) { *this = Student(n, nullptr, 0, ""); } Student::Student(int sn, const float* g, int ng_, const string& c) { 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 2021/8/8 Encapsulation | Input and Output Operators https://ict.senecacollege.ca/~oop244/pages/content/custo.html 10/11 no = sn; ng = ng_ < NG ? ng_ : NG; for (int i = 0; i < ng; i++) grade[i] = g[i]; comment = c; } else { *this = Student(); } } void Student::read(std::istream& is) { int no; // will hold the student number int ng; // will hold the number of grades float grade[NG]; // will hold the grades string comment; // will hold comments cout << "Student Number : "; is >> no;
cout << "Number of Grades : "; is >> ng;
if (ng > NG) ng = NG;
for (int i = 0; i < ng; i++) { cout << "Grade " << i + 1 << " : "; is >> grade[i];
}
is.ignore(); // extract newline
cout << "Comments : "; getline(is, comment, '\n'); // construct a temporary Student Student temp(no, grade, ng, comment); // if data is valid, the temporary object into the current object if (temp.no != 0) *this = temp; } void Student::display(std::ostream& os) const { if (no > 0) {
os << no << ":\n"; os.setf(ios::fixed); os.precision(2); for (int i = 0; i < ng; i++) { os.width(6); os << grade[i] << endl; } os.unsetf(ios::fixed); os.precision(6); os << "Comments:\n" << comment << endl; } else { os << "no data available" << endl; } } std::ostream& operator<<(std::ostream& os, const Student& s) { s.display(os); return os; } std::istream& operator>>(std::istream& is, Student& s) {
s.read(is);
return is;
}

The client code on the left receives the input on the right and produces the output listed below:

// String Class
// string.cpp

#include
#include “Student.h”

int main ( ) {
Student harry;

Student Number : 1234
Number of Grades : 2
Grade 1 : 56.7
Grade 2 : 78.9
Comments : See Coordinator

1234:

2021/8/8 Encapsulation | Input and Output Operators

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

std::cin >> harry;
std::cout << harry << std::endl; } 56.70 78.90 Comments: See Coordinator SUMMARY we associate our own classes with the iostream classes by overloading the extraction and insertion operators as helpers to those classes the first parameter in the declaration of each overloaded operator is a modifiable reference to the stream object the return type of each overloaded operator is a modifiable reference to the stream object, which enables cascading the standard library includes overloaded extraction and insertion operators for file objects as left operands and fundamental types as right operands an input file object is an instance of an ifstream class an output file object is an instance of an ofstream class the string class of the standard library manages the memory requirements for storing a user-defined character string of any length EXERCISES Complete the Handout on Custom I/O Operators. print this page Top Previous: Helper Functions Next: Inheritance 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/h10.html https://ict.senecacollege.ca/~oop244/pages/content/custo_p.html https://ict.senecacollege.ca/~oop244/pages/content/nonme.html https://ict.senecacollege.ca/~oop244/pages/content/inher.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/