Unit 3: Constructors, Destructors and Managing File Operations
I. Orientation
Object-oriented C++ manages object lifetime through constructors and destructors, while file streams extend a program’s storage beyond temporary memory. A constructor establishes an object’s initial state when it is created; a destructor releases resources when the object’s lifetime ends. File operations use stream objects to transfer character or binary data between a program and an external file.
- Object lifetime: Begins when an object is created and ends when it leaves scope or is explicitly destroyed.
- Resource ownership: A class that acquires a file, memory block, or device resource should release it reliably.
- Encapsulation: Data and the functions operating on it are grouped inside classes or structures.
- Stream model: Input reads data into a program; output writes data from a program.
- Text versus binary data: Text files store readable character representations, while binary files store bytes in their internal representation.
- Access discipline: Files should be opened with an appropriate mode, checked for failure, processed, and closed.
II. Constructors
Constructors are special member functions that establish valid initial values for objects. They are called automatically during object creation and may be overloaded to support different initialization requirements.
A. Features of constructor function
A constructor has a special syntax and a specific role in object initialization.
- Name: Its name is exactly the class name, such as
Student::Student(). - No return type: A constructor declares neither
voidnor any other return type. - Automatic invocation:
Student s;calls a suitable constructor without an explicit function call. - Overloading: A class may define multiple constructors with different parameter lists.
- Initialization purpose: Constructors should establish invariants, such as ensuring
marksstarts between0and100. - No inheritance of constructors in the traditional sense: A derived object invokes a base constructor, but it has its own construction process.
B. Default constructor
A default constructor can be called without arguments and creates an object with default state.
- User-defined form:
CPPclass Counter { int value; public: Counter() : value(0) {} };
Counter c;initializesvalueto0. - Compiler-generated form: If no constructor is declared, C++ may generate a default constructor, but built-in data members such as
int value;are not automatically initialized to a useful value. - Explicit defaulting:
Counter() = default;requests the compiler-generated behavior. - Use: Default construction is required by containers and algorithms when objects must be created before later assignment.
C. Constructor vs normal function
A constructor differs from an ordinary member function in purpose, invocation, and return behavior.
- Invocation: A constructor runs automatically at object creation;
display()must be called explicitly. - Return value: A constructor has no return type and cannot return a value; a normal function may return
int,double, or another type. - Object identity: A constructor initializes the object whose creation triggered it; a normal function operates on an already existing object.
- Call restrictions: Constructors cannot be called like ordinary functions using a return expression, although explicit temporary construction such as
Point(2, 3)is valid.
D. Parameterized constructor
A parameterized constructor accepts values needed to initialize an object with caller-supplied state.
- Definition:
CPPclass Rectangle { int width, height; public: Rectangle(int w, int h) : width(w), height(h) {} int area() const { return width * height; } }; - Construction:
Rectangle r(4, 5);creates an object whose area is20. - Validation: Constructor bodies can reject or normalize invalid values, although exceptions are generally preferable for construction failure.
- Effect on default construction: Declaring only
Rectangle(int, int)meansRectangle r;is invalid unless a default constructor is also supplied.
E. Copy constructor
A copy constructor initializes a new object from an existing object of the same class.
- Canonical signature:
CPPClassName(const ClassName& other);
The reference avoids copying again, andconstpermits copying from const objects. - Implicit uses:
Account b = a;, passing an object by value, and returning an object by value may invoke it. - Shallow-copy risk: A raw pointer member copies only an address, causing two objects to refer to the same resource.
- Deep copy: A resource-owning class should duplicate the resource rather than merely duplicate its pointer.
- Rule of three: If a class defines a destructor, copy constructor, or copy-assignment operator for resource management, it often needs all three.
F. Initializer lists
An initializer list constructs data members before the constructor body executes.
- Syntax:
CPPclass Employee { const int id; std::string name; public: Employee(int i, std::string n) : id(i), name(std::move(n)) {} }; - Mandatory cases:
constmembers, reference members, and members without default constructors must be initialized in the list. - Efficiency:
name(std::move(n))constructs the member directly, avoiding a default construction followed by assignment. - Order rule: Members initialize in their declaration order, not the order written in the list. Therefore, declare dependent members carefully.
G. Constructor with default arguments
Default arguments allow one constructor definition to support multiple call forms.
- Example:
CPPclass Date { int day, month, year; public: Date(int d, int m = 1, int y = 2025) : day(d), month(m), year(y) {} };
Date a(10);means day10, month1, year2025. - Right-to-left rule: Once a parameter has a default value, parameters to its right must also have defaults.
- Ambiguity: Combining a default-argument constructor with another overload may make calls such as
Date(10)ambiguous. - Declaration practice: Put default arguments in the function declaration, usually in the class definition, not redundantly in the definition.
III. Destructors
A destructor performs cleanup when an object’s lifetime ends. Its purpose is resource release, not ordinary data processing.
A. Destructor
A destructor is named with the class name preceded by ~ and takes no parameters.
- Syntax:
CPPclass Buffer { int* data; public: Buffer() : data(new int[10]) {} ~Buffer() { delete[] data; } }; - Automatic call: A local object is destroyed at the closing brace of its scope; dynamically allocated objects require
delete. - Reverse order: Local objects are destroyed in reverse order of construction, supporting dependency cleanup.
- Single destructor: A class cannot overload destructors because destruction requires no distinguishing arguments.
- Virtual destruction: A polymorphic base class should generally have a virtual destructor so
delete basePtr;correctly destroys a derived object. - RAII principle: Resource Acquisition Is Initialization ties ownership to object lifetime, making cleanup automatic and exception-safe.
IV. File Streams
C++ file processing is provided mainly by <fstream>, whose stream classes represent external files.
A. Opening and closing of files
Opening associates a stream object with a file; closing ends that association and flushes pending output.
- Output:
CPP#include <fstream> std::ofstream out("report.txt"); if (!out) { /* opening failed */ } out << "Total = " << 42 << '\n'; out.close(); - Input:
std::ifstream in("report.txt");opens a file for reading. - Combined access:
std::fstream file("data.txt", std::ios::in | std::ios::out);. - Failure checking:
is_open()checks association;fail()oroperator!detects operational failure. - Automatic closing: A stream destructor closes its associated file, but explicit
close()clearly marks the end of processing and allows another file to be opened.
B. Modes of file
File modes specify how a stream opens and positions a file.
ios::in: Opens for input; used byifstream.ios::out: Opens for output; an existing file may be truncated.ios::app: Positions every write at the end, useful for logs.ios::ate: Opens and initially positions at the end, but later seeking is allowed.ios::trunc: Erases existing contents when opening for output.ios::binary: Disables text translations and preserves byte-oriented data.- Combination:
std::ofstream log("app.log", std::ios::app);appends records rather than replacing the log.
C. File stream functions
Stream functions control reading state, positioning, and error detection.
- Character operations:
get(ch)reads one character;put(ch)writes one character. - Line operations:
getline(in, line)reads until a newline into astd::string. - State functions:
eof()reports an end-of-file condition, whilefail()reports a failed operation. Usewhile (std::getline(in, line)), notwhile (!in.eof()). - Position functions:
tellg()andseekg()query or change the input position;tellp()andseekp()do the same for output. - Buffer control:
flush()forces buffered output to the file. - Formatted operations:
>>extracts typed values and<<inserts formatted values.
V. File Processing Methods
The access method determines how records are located and updated.
A. Reading and writing of files
Reading transfers file content into variables; writing transfers formatted or raw program data into a stream.
- Formatted writing:
CPPstd::ofstream out("marks.txt"); out << "Asha " << 87 << '\n';
stores a human-readable record. - Formatted reading:
std::string name; int mark; in >> name >> mark;extracts whitespace-separated values. - Line-oriented reading:
std::getline(in, line)preserves spaces within a line. - Validation: Check the stream after opening and after important operations because permissions, missing files, or disk errors can fail.
- Format limitation: Formatted text is portable and readable, but it requires parsing and may lose exact object representation.
B. Sequential access and random access for file processing
Sequential access processes records in stored order, while random access jumps directly to a selected byte position.
- Sequential access: A loop reads record 1, then record 2, and so on; it is suitable for reports and ordinary text files.
- Random access: For fixed-size binary records,
seekg(index * sizeof(Record), std::ios::beg)moves to recordindex. - Position units:
seekgandseekpuse byte offsets represented by stream positions. - Contrast:
- Sequential: Simple and effective for variable-length lines, but finding the last record may require scanning earlier records.
- Random: Efficient for fixed-size records, but record layout and byte offsets must remain compatible.
- End positioning:
seekg(0, std::ios::end)moves to the end;tellg()can then measure file size.
VI. Binary and Structured File Operations
Binary processing is useful when exact bytes, compact storage, or direct record access is required.
A. Binary file operations
Binary streams read and write blocks of bytes using read() and write().
- Example:
CPPstruct Item { int id; double price; }; Item x{7, 19.5}; std::ofstream out("items.dat", std::ios::binary); out.write(reinterpret_cast<const char*>(&x), sizeof x); - Reading:
in.read(reinterpret_cast<char*>(&x), sizeof x);fillsxwith the nextsizeof xbytes. - Efficiency: One block operation can process a complete fixed-size record more efficiently than repeated formatted insertion.
- Portability limitation: Padding, byte order, type sizes, and compiler representation can differ between systems.
- Pointer warning: Never directly serialize a class containing a pointer and expect pointed-to data to be saved; the pointer value is only an address.
B. Classes and file operations
Classes can encapsulate file ownership and expose controlled persistence operations.
- Encapsulation: A class may keep
std::fstream file;private and providesave()andload()member functions. - Object serialization: Write each meaningful data member in a defined order rather than dumping an arbitrary object containing pointers or virtual-table data.
- Resource safety: The class destructor closes the stream automatically, while constructor logic can open and validate it.
- Invariant protection:
load()should validate values such as an employee ID being positive before accepting them. - Copy concern: Stream objects are not generally copied freely; resource-owning file classes should define or disable copying deliberately.
C. Structures and file operations
Structures can represent simple records whose fields are stored and retrieved in a predictable order.
- Text record: A
Studentstructure withint roll; char name[30]; float marks;can be written as formatted fields for readability. - Binary record: A trivially copyable structure can sometimes be written with
write(), provided portability and padding concerns are accepted. - Array processing:
Student students[50];can be processed sequentially, while fixed-size records permit indexed seeking. - Safe design: Prefer explicit field-by-field serialization when files must survive compiler, platform, or program-version changes.
- Practical distinction: Structures mainly group data; classes can additionally enforce invariants, manage streams, and provide behavior through member functions.
Did this save you a night before the exam?
LPU Notes is free, and it stays free. Ads cover part of the server bill. The rest comes out of a student's own pocket: the domain, the storage, and keeping the site up through the weeks everyone needs it at once.
The payment button didn't load. An ad blocker or a filtered network is the usual reason. to try again.
Nothing here is ever locked, and nothing unlocks. Chip in only if it was worth it. What it pays for →