C++ keeps the input/output system from C, but adds its own, built on the principles of object-oriented programming: safer, more flexible, and extensible to user-defined types. This final lab also makes the transition from structures to classes.
1Lab objectives
- Using the
cin,cout,cerr, andclogstreams - Formatting output with manipulators
- Working with files through
ifstreamandofstream - Defining a class with data members and member functions
- Writing constructors and the destructor
- Applying the encapsulation principle
2The I/O class hierarchy
Input/output operations are carried out using two class hierarchies, declared in the files
iostream.h and fstream.h:
3Predefined streams
| Stream | Meaning | Default device | C equivalent |
|---|---|---|---|
cin | standard input | keyboard | stdin |
cout | standard output | screen | stdout |
cerr | standard output for errors | screen | stderr |
clog | output for errors, buffered | screen | - |
<< is the insertion (writing)
operator, >> the extraction (reading) one. Both are overloaded operators,
which allows chaining: cout << a << " " << b << endl;cout << object works naturally.4Format manipulators
| Manipulator | Effect | Header needed |
|---|---|---|
endl | new line + flushing the buffer | iostream |
setw(n) | minimum width of n characters | iomanip |
setprecision(n) | the number of significant digits | iomanip |
fixed | fixed decimal notation | iostream |
scientific | scientific notation | iostream |
left / right | alignment within the field | iostream |
setfill(c) | the fill character | iomanip |
hex / oct / dec | the number base | iostream |
boolalpha | prints true/false instead of 1/0 | iostream |
setw acts only on the next
value printed, then it resets. The other manipulators (fixed,
setprecision, hex) stay active until changed again.5Files in C++
| Class | Role | C equivalent |
|---|---|---|
ifstream | reading from a file | fopen(..., "r") |
ofstream | writing to a file | fopen(..., "w") |
fstream | reading and writing | fopen(..., "r+") |
fclose is no longer possible - this is
the first concrete benefit of the object-oriented approach.6Classes and objects
A class extends the notion of a structure: besides data, it also contains the functions that operate on it. An object is a concrete instance of a class.
class ClassName {
private: // default for class
type data_members; // accessible only from inside the class
public:
ClassName(); // default constructor
ClassName(parameters); // constructor with parameters
~ClassName(); // destructor
type member_function(...); // public interface
};
| Specifier | Access from inside the class | From outside | From derived classes |
|---|---|---|---|
private | yes | no | no |
protected | yes | no | yes |
public | yes | yes | yes |
private for class, public for struct.
Otherwise, a C++ structure can have member functions, constructors, and a destructor.Constructors and destructor
| Element | When it is called | Characteristics |
|---|---|---|
| Constructor | when the object is created | has the class's name, returns nothing, can be overloaded |
| Copy constructor | when initialized from another object | ClassName(const ClassName &other) |
| Destructor | when the object is destroyed | ~ClassName(), unique, no parameters |
7Simulator: the life cycle of an object
Watch the exact moments when the constructor and destructor are called, including for objects created inside an inner block.
8Encapsulation
Data members are declared private, and access happens exclusively through public
functions. The advantage is not hiding for its own sake, but control: every change can be
validated.
class Temperature {
private:
double celsius;
public:
// without encapsulation, anyone could write t.celsius = -500;
bool setCelsius(double v) {
if (v < -273.15) return false; // validation: absolute zero
celsius = v;
return true;
}
double getCelsius() const { return celsius; }
double getFahrenheit() const { return celsius * 9.0 / 5.0 + 32.0; }
};
const guarantees
that it does not modify the object's state. The compiler checks the promise and reports any
violation - a simple and effective form of executable documentation.9Source code
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
double pi = 3.14159265358979;
cout << "Default: " << pi << endl;
cout << "fixed, 4 dec: " << fixed << setprecision(4) << pi << endl;
cout << "scientific: " << scientific << pi << endl;
cout << fixed << setprecision(2);
// aligned table
cout << "\n" << left << setw(14) << "Product"
<< right << setw(8) << "Qty"
<< setw(10) << "Price" << endl;
cout << setfill('-') << setw(32) << "" << setfill(' ') << endl;
cout << left << setw(14) << "Resistor"
<< right << setw(8) << 120 << setw(10) << 0.15 << endl;
cout << left << setw(14) << "Capacitor"
<< right << setw(8) << 45 << setw(10) << 0.80 << endl;
// number bases
int v = 255;
cout << "\n" << dec << v << " = " << hex << v
<< " (hex) = " << oct << v << " (oct)" << dec << endl;
cout << boolalpha << "\n3 > 5 is " << (3 > 5) << endl;
return 0;
}
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
class Student {
private:
string name;
int age;
double average;
public:
// default constructor
Student() : name("unknown"), age(0), average(0.0) {
cout << " [default constructor]" << endl;
}
// constructor with parameters, using the initialization list
Student(string n, int a, double m) : name(n), age(a), average(m) {
cout << " [constructor for " << name << "]" << endl;
}
// copy constructor
Student(const Student &other)
: name(other.name), age(other.age), average(other.average) {
cout << " [copy for " << name << "]" << endl;
}
~Student() {
cout << " [destructor for " << name << "]" << endl;
}
// access functions, with validation
bool setAverage(double m) {
if (m < 1.0 || m > 10.0) return false;
average = m;
return true;
}
string getName() const { return name; }
double getAverage() const { return average; }
bool passed() const { return average >= 5.0; }
void print() const {
cout << left << setw(18) << name
<< right << setw(4) << age << " years"
<< setw(8) << fixed << setprecision(2) << average
<< " " << (passed() ? "passed" : "failed") << endl;
}
};
int main()
{
cout << "Creating objects:" << endl;
Student s1("John Smith", 20, 9.15);
Student s2("Mary Johnson", 21, 4.30);
Student s3 = s1; // calls the copy constructor
cout << "\nList:" << endl;
s1.print();
s2.print();
s3.print();
cout << "\nAttempt to set the average to 15: ";
cout << (s2.setAverage(15.0) ? "accepted" : "REJECTED by validation") << endl;
cout << "\nDestruction (reverse order):" << endl;
return 0;
}
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
// writing
{
ofstream fout("data_cpp.txt");
if (!fout) { cerr << "Cannot write!" << endl; return 1; }
fout << "John Smith 20 9.15" << endl;
fout << "Mary Johnson 21 8.70" << endl;
} // the file closes AUTOMATICALLY here, through the destructor
// reading
ifstream fin("data_cpp.txt");
if (!fin) { cerr << "Cannot read!" << endl; return 1; }
string firstName, lastName;
int age;
double average;
cout << "File contents:" << endl;
while (fin >> firstName >> lastName >> age >> average) {
cout << " " << firstName << " " << lastName
<< ", " << age << " years, average " << average << endl;
}
fin.close();
// reading line by line
ifstream f2("data_cpp.txt");
string line;
int nr = 0;
cout << "\nLine by line:" << endl;
while (getline(f2, line)) {
cout << " " << ++nr << ": " << line << endl;
}
return 0;
}
10Code workshop
The boxes also accept C++: cout, string, classes
with constructors and destructors. Watch the output for the exact moment each one is called.
b is destroyed at the closing brace of
the inner block, not at the end of main. An object's lifetime is tied to the scope
in which it was declared.11Work tasks
- Print an aligned table using
setw,left,right, andsetfill. - Experimentally verify that
setwacts only on the next value printed. - Define a
Pointclass with private coordinates and methods for the distance to the origin. - Add to the class a default constructor, one with parameters, and a destructor that prints messages.
- Watch the console for the order of calls for several objects, including inside an inner block.
- Implement data validation in the
set-type functions and test disallowed values. - Write and read data from a file using
ofstreamandifstream. - Compare the C++ version with the C version of the same program and note the differences in readability.
12Extended application
Vector class that manages a
dynamically allocated array: a constructor with a size, a copy constructor, a destructor that
releases the memory, an add method with automatic resizing, bounds-checked access, and
overloading of the << operator for direct printing with cout. Add
saving to and loading from a file. Use messages in the constructor and destructor to verify that
no memory leaks occur.