Implementing C++ Classes with Constructors, Friends, and Static Members
Class T: Demonstrating Constructors and Static Members
Header File: T.h
#pragma once
#include <string>
class T {
public:
T(int val1 = 0, int val2 = 0);
T(const T &source);
T(T &&source);
~T();
void scale(int factor);
void show() const;
static int current_count();
static const std::string description;
static const int max_instances;
private:
int data1, data2;
static int instance_count;
friend void helper_function();
};
void helper_function();
Implementation File: T.cpp
#include "T.h"
#include <iostream>
const std::string T::description{"Basic class example"};
const int T::max_instances = 999;
int T::instance_count = 0;
int T::current_count() {
return instance_count;
}
T::T(int val1, int val2): data1{val1}, data2{val2} {
++instance_count;
std::cout << "T constructor executed.\n";
}
T::T(const T &source): data1{source.data1}, data2{source.data2} {
++instance_count;
std::cout << "T copy constructor executed.\n";
}
T::T(T &&source): data1{source.data1}, data2{source.data2} {
++instance_count;
std::cout << "T move constructor executed.\n";
}
T::~T() {
--instance_count;
std::cout << "T destructor executed.\n";
}
void T::scale(int factor) {
data1 *= factor;
data2 *= factor;
}
void T::show() const {
std::cout << "(" << data1 << ", " << data2 << ")";
}
void helper_function() {
T temp(42);
temp.data2 = 2049;
std::cout << "temp = "; temp.show(); std::cout << '\n';
}
Test Program: Task1.cpp
#include "T.h"
#include <iostream>
void test_class_T();
int main() {
std::cout << "Testing Class T: \n";
test_class_T();
std::cout << "\nTesting friend function: \n";
helper_function();
}
void test_class_T() {
using std::cout;
using std::endl;
cout << "Class info: " << T::description << endl;
cout << "Maximum instances: " << T::max_instances << endl;
cout << "Current instances: " << T::current_count() << endl << endl;
T obj1;
cout << "obj1 = "; obj1.show(); cout << endl;
T obj2(3, 4);
cout << "obj2 = "; obj2.show(); cout << endl;
T obj3(obj2);
obj3.scale(2);
cout << "obj3 = "; obj3.show(); cout << endl;
T obj4(std::move(obj2));
cout << "obj4 = "; obj4.show(); cout << endl;
cout << "Current instances: " << T::current_count() << endl;
}
Constructor Functions:
- The default constructor initializes new objects with member values.
- The copy constructor duplicates an existing obejct's state.
- The move constructor transfers resources from temporary objects efficiently.
- The destructor releases resources when objects are destroyed.
Static Members:
- Static data members maintain class-wide information.
- Static member functions operate on class-level data.
Complex Number Class with Friend Functions
Header File: Complex.h
#ifndef COMPLEX_H
#define COMPLEX_H
#include <string>
class Complex {
private:
double real_part;
double imag_part;
public:
static const std::string description;
Complex();
Complex(double real);
Complex(double real, double imag);
Complex(const Complex& other);
double real() const;
double imag() const;
void combine(const Complex& other);
friend void display(const Complex& c);
friend double magnitude(const Complex& c);
friend Complex sum(const Complex& c1, const Complex& c2);
friend bool equal(const Complex& c1, const Complex& c2);
friend bool not_equal(const Complex& c1, const Complex& c2);
};
void display(const Complex& c);
double magnitude(const Complex& c);
Complex sum(const Complex& c1, const Complex& c2);
bool equal(const Complex& c1, const Complex& c2);
bool not_equal(const Complex& c1, const Complex& c2);
#endif
Implementation File: Complex.cpp
#include "Complex.h"
#include <iostream>
#include <cmath>
using namespace std;
const string Complex::description = "Simplified complex number class";
Complex::Complex() : real_part(0.0), imag_part(0.0) {}
Complex::Complex(double real) : real_part(real), imag_part(0.0) {}
Complex::Complex(double real, double imag) : real_part(real), imag_part(imag) {}
Complex::Complex(const Complex& other) : real_part(other.real_part), imag_part(other.imag_part) {}
double Complex::real() const { return real_part; }
double Complex::imag() const { return imag_part; }
void Complex::combine(const Complex& other) {
real_part += other.real_part;
imag_part += other.imag_part;
}
void display(const Complex& c) {
cout << c.real_part;
if (c.imag_part >= 0) {
cout << " + " << c.imag_part << "i";
} else {
cout << " - " << -c.imag_part << "i";
}
}
double magnitude(const Complex& c) {
return sqrt(c.real_part * c.real_part + c.imag_part * c.imag_part);
}
Complex sum(const Complex& c1, const Complex& c2) {
return Complex(c1.real_part + c2.real_part, c1.imag_part + c2.imag_part);
}
bool equal(const Complex& c1, const Complex& c2) {
return (c1.real_part == c2.real_part) && (c1.imag_part == c2.imag_part);
}
bool not_equal(const Complex& c1, const Complex& c2) {
return !equal(c1, c2);
}
Friend Functions:
- Friend functions access private members with out being class members.
- Use friend declarations when functions need direct data access but shouldn't be member functions.
- Standard library functions like
abs()forstd::complexdon't require friend status because they use public interfaces.
Player Control System with Enumeration
Header File: PlayerControl.h
#pragma once
#include <string>
enum class Command {Play, Pause, Next, Previous, Stop, Invalid};
class PlayerControl {
public:
PlayerControl();
Command interpret(const std::string& input);
void process(Command instruction) const;
static int command_count();
private:
static int total_commands;
};
Implementation File: PlayerControl.cpp
#include "PlayerControl.h"
#include <iostream>
#include <algorithm>
#include <cctype>
int PlayerControl::total_commands = 0;
PlayerControl::PlayerControl() {}
Command PlayerControl::interpret(const std::string& input) {
std::string lowercase = input;
std::transform(lowercase.begin(), lowercase.end(), lowercase.begin(),
[](unsigned char ch) { return std::tolower(ch); });
if (lowercase == "play") {
total_commands++;
return Command::Play;
} else if (lowercase == "pause") {
total_commands++;
return Command::Pause;
} else if (lowercase == "next") {
total_commands++;
return Command::Next;
} else if (lowercase == "prev") {
total_commands++;
return Command::Previous;
} else if (lowercase == "stop") {
total_commands++;
return Command::Stop;
} else {
return Command::Invalid;
}
}
void PlayerControl::process(Command instruction) const {
switch (instruction) {
case Command::Play: std::cout << "[Play] Starting playback...\n"; break;
case Command::Pause: std::cout << "[Pause] Playback paused\n"; break;
case Command::Next: std::cout << "[Next] Advancing to next track\n"; break;
case Command::Previous: std::cout << "[Previous] Returning to previous track\n"; break;
case Command::Stop: std::cout << "[Stop] Playback stopped\n"; break;
default: std::cout << "[Error] Unrecognized command\n"; break;
}
}
int PlayerControl::command_count() {
return total_commands;
}
Fraction Class with Arithmetic Operations
Header File: Fraction.h
#pragma once
#include <string>
class Fraction {
public:
static const std::string description;
Fraction(int numerator = 0, int denominator = 1);
Fraction(const Fraction& other);
int numerator() const;
int denominator() const;
Fraction opposite() const;
private:
int num;
int den;
void reduce();
int common_divisor(int a, int b) const;
};
void print(const Fraction& f);
Fraction plus(const Fraction& f1, const Fraction& f2);
Fraction minus(const Fraction& f1, const Fraction& f2);
Fraction times(const Fraction& f1, const Fraction& f2);
Fraction divide(const Fraction& f1, const Fraction& f2);
Implementation File: Fraction.cpp
#include "Fraction.h"
#include <iostream>
#include <stdexcept>
#include <cmath>
using namespace std;
const string Fraction::description = "Fraction class v0.01\nSupports construction, display, and basic arithmetic.";
Fraction::Fraction(int numerator, int denominator) : num(numerator), den(denominator) {
if (denominator == 0) {
throw invalid_argument("Denominator cannot be zero");
}
if (denominator < 0) {
num = -numerator;
den = -denominator;
}
reduce();
}
Fraction::Fraction(const Fraction& other) : num(other.num), den(other.den) {}
int Fraction::numerator() const { return num; }
int Fraction::denominator() const { return den; }
Fraction Fraction::opposite() const {
return Fraction(-num, den);
}
int Fraction::common_divisor(int a, int b) const {
a = abs(a);
b = abs(b);
while (b != 0) {
int remainder = b;
b = a % b;
a = remainder;
}
return a;
}
void Fraction::reduce() {
if (num == 0) {
den = 1;
return;
}
int divisor = common_divisor(num, den);
num /= divisor;
den /= divisor;
}
void print(const Fraction& f) {
if (f.denominator() == 1) {
cout << f.numerator();
} else {
cout << f.numerator() << "/" << f.denominator();
}
}
Fraction plus(const Fraction& f1, const Fraction& f2) {
int new_num = f1.numerator() * f2.denominator() + f2.numerator() * f1.denominator();
int new_den = f1.denominator() * f2.denominator();
return Fraction(new_num, new_den);
}
Fraction minus(const Fraction& f1, const Fraction& f2) {
int new_num = f1.numerator() * f2.denominator() - f2.numerator() * f1.denominator();
int new_den = f1.denominator() * f2.denominator();
return Fraction(new_num, new_den);
}
Fraction times(const Fraction& f1, const Fraction& f2) {
int new_num = f1.numerator() * f2.numerator();
int new_den = f1.denominator() * f2.denominator();
return Fraction(new_num, new_den);
}
Fraction divide(const Fraction& f1, const Fraction& f2) {
if (f2.numerator() == 0) {
throw invalid_argument("Division by zero");
}
int new_num = f1.numerator() * f2.denominator();
int new_den = f1.denominator() * f2.numerator();
return Fraction(new_num, new_den);
}