Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Implementing C++ Classes with Constructors, Friends, and Static Members

Tech 1

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() for std::complex don'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);
}
Tags: C++

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.