Skills Check 3 Flashcards
What is the purpose of constructors and destructors in object-oriented programming? How are they implemented in C++? Provide examples.
include <iostream>
🏗️ Constructor:
A constructor is automatically called when an object is created.
Its main job is to initialize the object (set default or user-defined values).
🧹 Destructor:
A destructor is automatically called when an object goes out of scope or is deleted.
Its main job is to clean up (like releasing memory or closing files).
example:
using namespace std;
class Car {
private:
string brand;
public:
// Constructor Car(string b) { brand = b; cout << "Constructor called: " << brand << endl; } void showBrand() { cout << "Brand: " << brand << endl; } // Destructor ~Car() { cout << "Destructor called: " << brand << endl; }
};
int main() {
Car car1("Toyota"); // Constructor is automatically called car1.showBrand(); { // Nested scope Car car2("Honda"); car2.showBrand(); } // Destructor for car2 is called here return 0; // Destructor for car1 is called here
}
What is the difference between initializing class data members using an initializer list and initializing them within the constructor’s function body? Provide examples.
When you initialize class data members in C++, you can do it in two main ways:
Using an initializer list (recommended)
Inside the constructor’s function body
✅ Key Difference:
The initializer list sets the values before the constructor’s body runs, while assigning inside the constructor body sets the values after the object is created.
examples:
class MyClass {
int a; int b;
public:
// Using initializer list MyClass() : a(10), b(20) { // constructor body } // vs. initializing inside the constructor body // MyClass() { // a = 10; // b = 20; // }
};
Implement in C++ a class, called Timer, which will store time information in hours, minutes, and seconds (i.e., HH:MM:SS), as three separate class data members. The class should contain: (1) a default constructor with initialization to 00:00:00 that takes place before the constructor starts to execute, and (2) a pair of get/set methods that will (a) display on the screen the time currently stored in the object, and (b) set an arbitrary time to the object, respectively. Test your code by creating one object of the Timer class in the main function of your program.
include <iostream></iostream>
#include <iomanip></iomanip>
class Timer {
private:
int hours;
int minutes;
int seconds;
public:
// Default constructor with member initializer list
Timer() : hours(0), minutes(0), seconds(0) {
// Constructor body (optional)
}
// Method to set the time void setTime(int h, int m, int s) { // Optional: Add validation here if needed hours = h; minutes = m; seconds = s; } // Method to display the time in HH:MM:SS format void displayTime() const { std::cout << std::setfill('0') << std::setw(2) << hours << ":" << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds << std::endl; } };
int main() {
// Create a Timer object
Timer t;
// Display default time std::cout << "Default time: "; t.displayTime(); // Set time to a custom value t.setTime(13, 45, 30); std::cout << "Updated time: "; t.displayTime(); return 0; }
Extend the Timer class by adding a destructor, which will simply display the message on the screen that an object of the class is being destroyed, as it is being deleted.
include <iostream></iostream>
#include <iomanip></iomanip>
class Timer {
private:
int hours;
int minutes;
int seconds;
public:
// Default constructor with member initializer list
Timer() : hours(0), minutes(0), seconds(0) {
// Optional: Constructor message
}
// Destructor ~Timer() { std::cout << "Timer object is being destroyed." << std::endl; } // Method to set the time void setTime(int h, int m, int s) { hours = h; minutes = m; seconds = s; } // Method to display the time void displayTime() const { std::cout << std::setfill('0') << std::setw(2) << hours << ":" << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds << std::endl; } };
int main() {
{
// Create a Timer object inside a local block
Timer t;
std::cout «_space;“Default time: “;
t.displayTime();
t.setTime(9, 15, 42); std::cout << "Updated time: "; t.displayTime(); } // Timer object goes out of scope here and is destroyed std::cout << "Program ended." << std::endl; return 0; }
Overload the Timer constructor by adding an option to start the timer at any arbitrary time in hours, minutes, and seconds. The initialization should take place before the constructor starts to execute.
include <iostream></iostream>
#include <iomanip></iomanip>
class Timer {
private:
int hours;
int minutes;
int seconds;
public:
// Default constructor using member initializer list
Timer() : hours(0), minutes(0), seconds(0) {
std::cout «_space;“Default Timer constructed.\n”;
}
// Overloaded constructor to initialize to custom time Timer(int h, int m, int s) : hours(h), minutes(m), seconds(s) { std::cout << "Timer constructed with custom time.\n"; } // Destructor ~Timer() { std::cout << "Timer object is being destroyed." << std::endl; } // Set time void setTime(int h, int m, int s) { hours = h; minutes = m; seconds = s; } // Display time void displayTime() const { std::cout << std::setfill('0') << std::setw(2) << hours << ":" << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds << std::endl; } };
int main() {
{
// Using default constructor
Timer t1;
t1.displayTime();
// Using overloaded constructor Timer t2(14, 25, 59); t2.displayTime(); } // Both t1 and t2 destroyed here std::cout << "Program ended." << std::endl; return 0; }
Extend your Timer class by adding a method called add_time(…), which will allow you to add an arbitrary amount of time to an existing object of the class. Make sure that the time stored in an object of the class Timer is in the appropriate format (HH:MM:SS), although the value of hours should not be limited to just two digits. This function should be defined outside of the class. Test your method to make sure that it works properly.
include <iostream></iostream>
#include <iomanip></iomanip>
class Timer {
private:
int hours;
int minutes;
int seconds;
public:
// Default constructor
Timer() : hours(0), minutes(0), seconds(0) {
std::cout «_space;“Default Timer constructed.\n”;
}
// Overloaded constructor Timer(int h, int m, int s) : hours(h), minutes(m), seconds(s) { std::cout << "Timer constructed with custom time.\n"; } // Destructor ~Timer() { std::cout << "Timer object is being destroyed." << std::endl; } // Set time void setTime(int h, int m, int s) { hours = h; minutes = m; seconds = s; } // Display time void displayTime() const { std::cout << std::setfill('0') << std::setw(2) << hours << ":" << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds << std::endl; } // Declare add_time method void add_time(int h, int m, int s); };
// Define add_time outside the class
void Timer::add_time(int h, int m, int s) {
seconds += s;
minutes += m + seconds / 60;
seconds %= 60;
hours += h + minutes / 60; minutes %= 60; }
int main() {
Timer t(1, 59, 50);
std::cout «_space;“Original time: “;
t.displayTime();
// Add arbitrary time t.add_time(2, 125, 85); // Add 2 hours, 125 minutes, 85 seconds std::cout << "After adding time: "; t.displayTime(); return 0; }
What is the purpose of a default copy constructor, and how is it implemented in C++? What are its advantages and limitations? Provide examples.
A copy constructor is a special constructor that creates a new object as a copy of an existing object.
🧠 Purpose of the Default Copy Constructor
Allows you to pass objects by value.
Enables returning objects from functions by value.
Creates copies of objects, e.g., MyClass b = a;
code example:
#include <iostream>
using namespace std;</iostream>
class Box {
private:
int length;
public:
// Constructor
Box(int l) {
length = l;
}
// Copy constructor Box(const Box &b) { length = b.length; } void showLength() { cout << "Length: " << length << endl; } };
int main() {
Box box1(10); // Create original box
Box box2 = box1; // Create a copy using copy constructor
box1.showLength(); // Output: Length: 10 box2.showLength(); // Output: Length: 10 return 0; }
In your main function, create two additional objects of the class Timer, based on the originally created object.
include <iostream></iostream>
#include <iomanip></iomanip>
class Timer {
private:
int hours;
int minutes;
int seconds;
public:
// Default constructor
Timer() : hours(0), minutes(0), seconds(0) {}
// Parameterized constructor Timer(int h, int m, int s) : hours(h), minutes(m), seconds(s) {} // Copy constructor Timer(const Timer& t) : hours(t.hours), minutes(t.minutes), seconds(t.seconds) {} // Display method void displayTime() const { std::cout << std::setfill('0') << std::setw(2) << hours << ":" << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds << std::endl; } };
int main() {
Timer original(8, 45, 20); // Original object
Timer copy1 = original; // First copy using copy constructor
Timer copy2(original); // Second copy using copy constructor
std::cout << "Original Time: "; original.displayTime(); std::cout << "Copy 1 Time: "; copy1.displayTime(); std::cout << "Copy 2 Time: "; copy2.displayTime(); return 0; }
Overload your add_time(…) method by implementing a version of the function, which will add time to an existing object of the class Timer based on another object of the same class. For example, if the object, to which you are adding time is presently storing the time of 11h:22m:33s, and the other object contains the values of 22 hours, 33 minutes, and 44 seconds, the final time in the first object, after the addition, should be: 33h:56m:17s. This function should also be defined outside of the class. Test the method to make sure that it works properly.
include <iostream></iostream>
#include <iomanip></iomanip>
class Timer {
private:
int hours;
int minutes;
int seconds;
public:
// Default constructor
Timer() : hours(0), minutes(0), seconds(0) {
std::cout «_space;“Default Timer constructed.\n”;
}
// Overloaded constructor Timer(int h, int m, int s) : hours(h), minutes(m), seconds(s) { std::cout << "Timer constructed with custom time.\n"; } // Copy constructor Timer(const Timer& other) : hours(other.hours), minutes(other.minutes), seconds(other.seconds) { std::cout << "Timer copied.\n"; } // Destructor ~Timer() { std::cout << "Timer object is being destroyed." << std::endl; } // Set time void setTime(int h, int m, int s) { hours = h; minutes = m; seconds = s; } // Display time void displayTime() const { std::cout << std::setfill('0') << std::setw(2) << hours << ":" << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds << std::endl; } // Declare add_time method void add_time(int h, int m, int s); };
// Define add_time outside the class
void Timer::add_time(int h, int m, int s) {
seconds += s;
minutes += m + seconds / 60;
seconds %= 60;
hours += h + minutes / 60; minutes %= 60; }
int main() {
// Original object
Timer t(1, 59, 50);
std::cout «_space;“Original time: “;
t.displayTime();
// Add arbitrary time to the original t.add_time(2, 125, 85); std::cout << "After adding time to t: "; t.displayTime(); // Create two new objects based on the original Timer t2 = t; // Using copy constructor Timer t3(t); // Also using copy constructor std::cout << "Time in t2 (copied from t): "; t2.displayTime(); std::cout << "Time in t3 (copied from t): "; t3.displayTime(); return 0; }
Overload your add_time(…) method by implementing a version of the function, which, instead of adding the time from one object to another, will take as parameters two objects of the class Timer, and return a third object of the same class, with the total time from the first two objects stored as the time in the third object. This function should also be defined outside of the class. Test the method to make sure that it works properly.
include <iostream></iostream>
#include <iomanip></iomanip>
class Timer {
private:
int hours;
int minutes;
int seconds;
public:
// Default constructor
Timer() : hours(0), minutes(0), seconds(0) {
std::cout «_space;“Default Timer constructed.\n”;
}
// Overloaded constructor Timer(int h, int m, int s) : hours(h), minutes(m), seconds(s) { std::cout << "Timer constructed with custom time.\n"; } // Copy constructor Timer(const Timer& other) : hours(other.hours), minutes(other.minutes), seconds(other.seconds) { std::cout << "Timer copied.\n"; } // Destructor ~Timer() { std::cout << "Timer object is being destroyed." << std::endl; } // Set time void setTime(int h, int m, int s) { hours = h; minutes = m; seconds = s; } // Display time void displayTime() const { std::cout << std::setfill('0') << std::setw(2) << hours << ":" << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds << std::endl; } // Instance add_time method void add_time(int h, int m, int s); // Friend declaration for non-member add_time friend Timer add_time(const Timer& t1, const Timer& t2); };
// Define instance method
void Timer::add_time(int h, int m, int s) {
seconds += s;
minutes += m + seconds / 60;
seconds %= 60;
hours += h + minutes / 60; minutes %= 60; }
// Define non-member overloaded function
Timer add_time(const Timer& t1, const Timer& t2) {
int totalSeconds = t1.seconds + t2.seconds;
int totalMinutes = t1.minutes + t2.minutes + totalSeconds / 60;
int totalHours = t1.hours + t2.hours + totalMinutes / 60;
totalSeconds %= 60; totalMinutes %= 60; return Timer(totalHours, totalMinutes, totalSeconds); }
// MAIN FUNCTION
int main() {
Timer t1(1, 40, 50);
Timer t2(3, 25, 30);
std::cout << "Timer t1: "; t1.displayTime(); std::cout << "Timer t2: "; t2.displayTime(); Timer t3 = add_time(t1, t2); // New object created from total std::cout << "Total time in t3 (t1 + t2): "; t3.displayTime(); return 0; }
What is the purpose of static class data? How are they different from const class data? Provide examples.
Static Purpose:
A static data member belongs to the class itself, not to any one object.
It’s shared by all objects of that class.
It can be used to keep track of data common to all objects (like a counter, config, or global setting).
example:
class Dog {
public:
static int dogCount; // Shared by all Dog objects
Dog() { dogCount++; // Each time a Dog is made, count goes up } static int getCount() { return dogCount; } };
// Must define static variable outside the class
int Dog::dogCount = 0;
int main() {
Dog d1, d2, d3;
std::cout «_space;“Number of dogs: “ «_space;Dog::getCount() «_space;std::endl;
return 0;
}
Const Purpose:
A const data member means its value can never change once it’s set.
It’s useful for fixed values like max sizes, rates, or names.
Each object can have its own const value, or it can be made static const to be shared.
class Circle {
private:
const double PI = 3.14159; // Value never changes
public:
double getArea(double radius) {
return PI * radius * radius;
}
};
int main() {
Circle c;
std::cout «_space;“Area: “ «_space;c.getArea(2) «_space;std::endl;
return 0;
}
Extend your Timer class by adding to it the capability of keeping count of how many objects of the class Timer have been created and are stored in the memory of the computer. Also, add a method called get_count(…), which will return the number of Timer objects presently stored in the memory of the computer. This method should be implemented inside of the class. Test the added capability of the class to make sure that it works properly.
include <iostream></iostream>
#include <iomanip></iomanip>
class Timer {
private:
int hours;
int minutes;
int seconds;
static int count; // static member to track number of Timer objects
public:
// Default constructor
Timer() : hours(0), minutes(0), seconds(0) {
count++;
std::cout «_space;“Default Timer constructed.\n”;
}
// Overloaded constructor Timer(int h, int m, int s) : hours(h), minutes(m), seconds(s) { count++; std::cout << "Timer constructed with custom time.\n"; } // Copy constructor Timer(const Timer& other) : hours(other.hours), minutes(other.minutes), seconds(other.seconds) { count++; std::cout << "Timer copied.\n"; } // Destructor ~Timer() { count--; std::cout << "Timer object is being destroyed." << std::endl; } // Static method to get count static int get_count() { return count; } // Set time void setTime(int h, int m, int s) { hours = h; minutes = m; seconds = s; } // Display time void displayTime() const { std::cout << std::setfill('0') << std::setw(2) << hours << ":" << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds << std::endl; } // Instance method void add_time(int h, int m, int s); // Friend for non-member add_time friend Timer add_time(const Timer& t1, const Timer& t2); };
// Initialize static count
int Timer::count = 0;
// Define instance add_time
void Timer::add_time(int h, int m, int s) {
seconds += s;
minutes += m + seconds / 60;
seconds %= 60;
hours += h + minutes / 60; minutes %= 60; }
// Non-member add_time function
Timer add_time(const Timer& t1, const Timer& t2) {
int totalSeconds = t1.seconds + t2.seconds;
int totalMinutes = t1.minutes + t2.minutes + totalSeconds / 60;
int totalHours = t1.hours + t2.hours + totalMinutes / 60;
totalSeconds %= 60; totalMinutes %= 60; return Timer(totalHours, totalMinutes, totalSeconds); }
// MAIN FUNCTION
int main() {
std::cout «_space;“Live Timer objects: “ «_space;Timer::get_count() «_space;“\n\n”;
Timer t1(1, 20, 30); std::cout << "Live Timer objects: " << Timer::get_count() << "\n\n"; { Timer t2(2, 40, 50); Timer t3 = add_time(t1, t2); std::cout << "Live Timer objects: " << Timer::get_count() << "\n\n"; } // t2 and t3 go out of scope std::cout << "Live Timer objects after block ends: " << Timer::get_count() << "\n\n"; return 0; }
Extend your Timer class by adding a ++ operator, which will, every time it is executed, add a second to the current time stored in an object of the class. Make sure that, after the increment, the time stored in the object is in the appropriate format (HH:MM:SS)! This operator should be defined inside of the class. Test the operator to make sure that it works properly.
include <iostream></iostream>
#include <iomanip></iomanip>
class Timer {
private:
int hours;
int minutes;
int seconds;
static int count;
public:
// Default constructor
Timer() : hours(0), minutes(0), seconds(0) {
count++;
std::cout «_space;“Default Timer constructed.\n”;
}
// Overloaded constructor Timer(int h, int m, int s) : hours(h), minutes(m), seconds(s) { count++; std::cout << "Timer constructed with custom time.\n"; } // Copy constructor Timer(const Timer& other) : hours(other.hours), minutes(other.minutes), seconds(other.seconds) { count++; std::cout << "Timer copied.\n"; } // Destructor ~Timer() { count--; std::cout << "Timer object is being destroyed." << std::endl; } // Static count getter static int get_count() { return count; } // Set time void setTime(int h, int m, int s) { hours = h; minutes = m; seconds = s; } // Display time void displayTime() const { std::cout << std::setfill('0') << std::setw(2) << hours << ":" << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds << std::endl; } // Instance add_time method void add_time(int h, int m, int s); // Friend for non-member add_time friend Timer add_time(const Timer& t1, const Timer& t2); // Overload ++ (prefix) to add 1 second Timer& operator++() { seconds += 1; if (seconds >= 60) { seconds = 0; minutes += 1; } if (minutes >= 60) { minutes = 0; hours += 1; } return *this; } };
// Static member definition
int Timer::count = 0;
// Instance add_time
void Timer::add_time(int h, int m, int s) {
seconds += s;
minutes += m + seconds / 60;
seconds %= 60;
hours += h + minutes / 60; minutes %= 60; }
// Friend non-member add_time
Timer add_time(const Timer& t1, const Timer& t2) {
int totalSeconds = t1.seconds + t2.seconds;
int totalMinutes = t1.minutes + t2.minutes + totalSeconds / 60;
int totalHours = t1.hours + t2.hours + totalMinutes / 60;
totalSeconds %= 60; totalMinutes %= 60; return Timer(totalHours, totalMinutes, totalSeconds); }
// MAIN FUNCTION
int main() {
Timer t(2, 59, 59);
std::cout «_space;“Before increment: “;
t.displayTime();
\++t; // Use overloaded ++ operator std::cout << "After increment: "; t.displayTime(); return 0; }
What is the difference between public, private, and protected access specifiers? Provide examples.
- public
Members are accessible from anywhere (inside or outside the class). - private
Members are only accessible within the class itself. - protected
Like private, but allows access in derived (child) classes. Great for inheritance.
public example:
class Dog {
public:
void bark() {
std::cout «_space;“Woof!” «_space;std::endl;
}
};
int main() {
Dog d;
d.bark(); // ✅ Accessible, because it’s public
return 0;
}
private example:
class BankAccount {
private:
int balance = 100;
public:
void showBalance() {
std::cout «_space;“Balance: $” «_space;balance «_space;std::endl;
}
};
int main() {
BankAccount acc;
acc.showBalance(); // ✅ OK
// std::cout «_space;acc.balance; // ❌ Error! ‘balance’ is private
return 0;
}
protected example:
class Animal {
protected:
std::string name = “Animal”;
};
class Cat : public Animal {
public:
void revealName() {
std::cout «_space;“I am a “ «_space;name «_space;std::endl; // ✅ Accessible in subclass
}
};
int main() {
Cat c;
c.revealName(); // ✅ OK
// std::cout «_space;c.name; // ❌ Error! ‘name’ is protected
return 0;
}
Create a new class called Countdown, which will derive from the original Timer class. The new class should have a – operator, which will subtract a second from the current time stored in an object of the class, but it will not go below 00:00:00.
include <iostream></iostream>
#include <iomanip></iomanip>
class Timer {
protected: // Protected so Countdown can access them
int hours;
int minutes;
int seconds;
static int count;
public:
Timer() : hours(0), minutes(0), seconds(0) {
count++;
std::cout «_space;“Default Timer constructed.\n”;
}
Timer(int h, int m, int s) : hours(h), minutes(m), seconds(s) { count++; std::cout << "Timer constructed with custom time.\n"; } Timer(const Timer& other) : hours(other.hours), minutes(other.minutes), seconds(other.seconds) { count++; std::cout << "Timer copied.\n"; } virtual ~Timer() { count--; std::cout << "Timer object is being destroyed." << std::endl; } static int get_count() { return count; } void setTime(int h, int m, int s) { hours = h; minutes = m; seconds = s; } void displayTime() const { std::cout << std::setfill('0') << std::setw(2) << hours << ":" << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds << std::endl; } void add_time(int h, int m, int s); friend Timer add_time(const Timer& t1, const Timer& t2); Timer& operator++() { seconds++; if (seconds >= 60) { seconds = 0; minutes++; } if (minutes >= 60) { minutes = 0; hours++; } return *this; } };
int Timer::count = 0;
void Timer::add_time(int h, int m, int s) {
seconds += s;
minutes += m + seconds / 60;
seconds %= 60;
hours += h + minutes / 60; minutes %= 60; }
Timer add_time(const Timer& t1, const Timer& t2) {
int totalSeconds = t1.seconds + t2.seconds;
int totalMinutes = t1.minutes + t2.minutes + totalSeconds / 60;
int totalHours = t1.hours + t2.hours + totalMinutes / 60;
totalSeconds %= 60; totalMinutes %= 60; return Timer(totalHours, totalMinutes, totalSeconds); }
// ——————-
// Countdown Class
// ——————-
class Countdown : public Timer {
public:
Countdown() : Timer() {}
Countdown(int h, int m, int s) : Timer(h, m, s) {}
Countdown& operator--() { if (hours == 0 && minutes == 0 && seconds == 0) { // Don't go below 00:00:00 return *this; } if (seconds > 0) { seconds--; } else { if (minutes > 0) { minutes--; seconds = 59; } else if (hours > 0) { hours--; minutes = 59; seconds = 59; } } return *this; } };
// ——————-
// MAIN FUNCTION
// ——————-
int main() {
Countdown c(0, 0, 2);
std::cout «_space;“Starting countdown: “;
c.displayTime();
--c; std::cout << "After first --: "; c.displayTime(); --c; std::cout << "After second --: "; c.displayTime(); --c; // Should stay at 00:00:00 std::cout << "After third -- (shouldn't go below 00:00:00): "; c.displayTime(); return 0; }