Code Examples (imp, head)
Calculator, using classes
Project Structure
Test Project/
│
├── src/
│ ├── main.cpp // Main file, uses Calculator class
│ └── calculator.cpp // Implementation of Calculator class
│
├── include/
│ └── calculator.h // Header file for Calculator class
include/calculator.h (header file)
// calculator.h (use ChatGPT to understand these two lines)
#ifndef CALCULATOR_H
#define CALCULATOR_H
// defines class interface
class Calculator {
public:
// Constructor
Calculator();
// Basic arithmetic operations
int add(int a, int b);
int subtract(int a, int b);
int multiply(int a, int b);
double divide(int a, int b);
// Destructor
~Calculator();
};
#endif // CALCULATOR_Hsrc/calculator.cpp (implementation file)
// calculator.cpp, include calculator header file
#include "calculator.h"
#include <stdexcept> // For handling divide-by-zero exception
// Constructor - "Calculator" is function name and it belongs to class Calculator. Constructor code isn't included in this example.
Calculator::Calculator() {
// Initialization code if needed
}
// Method for addition. Return type - What class belongs to - function name
int Calculator::add(int a, int b) {
return a + b;
}
// Method for subtraction
int Calculator::subtract(int a, int b) {
return a - b;
}
// Method for multiplication
int Calculator::multiply(int a, int b) {
return a * b;
}
// Method for division
double Calculator::divide(int a, int b) {
if (b == 0) {
throw std::invalid_argument("Division by zero is not allowed.");
}
return static_cast<double>(a) / b;
}
// Destructor
Calculator::~Calculator() {
// Cleanup code if needed
}src/main.cpp (main file)
// main.cpp, include header file
#include <iostream>
#include "calculator.h"
int main() {
Calculator calc; // Creating an instance of Calculator
int a = 10;
int b = 5;
std::cout << "Addition of " << a << " and " << b << ": " << calc.add(a, b) << std::endl;
std::cout << "Subtraction of " << a << " and " << b << ": " << calc.subtract(a, b) << std::endl;
std::cout << "Multiplication of " << a << " and " << b << ": " << calc.multiply(a, b) << std::endl;
try {
std::cout << "Division of " << a << " by " << b << ": " << calc.divide(a, b) << std::endl;
} catch (const std::invalid_argument& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
return 0;
}
As you can see, the files are linked by the line #include "calculator.h".This must be added to the implementation and the main file.
Scientific Calculator, using classes + inheritance
This is useful as we can create a new “scientific_calculator" class that inherits all the basic functions from the basic calculator class.
Updated Project Structure
Test Project/
│
├── src/
│ ├── main.cpp // Main file, uses Calculator and ScientificCalculator
│ ├── calculator.cpp // Implementation of Calculator class
│ └── scientific_calculator.cpp // Implementation of ScientificCalculator class
│
├── include/
│ ├── calculator.h // Header file for Calculator class
│ └── scientific_calculator.h // Header file for ScientificCalculator class
include/calculator.h
// calculator.h
#ifndef CALCULATOR_H
#define CALCULATOR_H
class Calculator {
public:
// Constructor
Calculator();
// Basic arithmetic operations
int add(int a, int b);
int subtract(int a, int b);
int multiply(int a, int b);
double divide(int a, int b);
// Destructor
virtual ~Calculator();
};
#endif // CALCULATOR_H
include/scientific_calculator.h
// scientific_calculator.h
#ifndef SCIENTIFIC_CALCULATOR_H
#define SCIENTIFIC_CALCULATOR_H
#include "calculator.h"
#include <cmath> // For sqrt() and pow() functions
// inherits from "Calculator". Meaning this class now includes all the public methods and data from the "Calculator" class.
class ScientificCalculator : public Calculator {
public:
// Constructor
ScientificCalculator();
// Advanced operations
double power(double base, double exponent);
double squareRoot(double value);
// Destructor
~ScientificCalculator();
};
#endif // SCIENTIFIC_CALCULATOR_H
src/calculator.cpp
// calculator.cpp
#include "calculator.h"
#include <stdexcept> // For handling divide-by-zero exception
Calculator::Calculator() {}
int Calculator::add(int a, int b) {
return a + b;
}
int Calculator::subtract(int a, int b) {
return a - b;
}
int Calculator::multiply(int a, int b) {
return a * b;
}
double Calculator::divide(int a, int b) {
if (b == 0) {
throw std::invalid_argument("Division by zero is not allowed.");
}
return static_cast<double>(a) / b;
}
Calculator::~Calculator() {}
src/scientific_calculator.cpp
// scientific_calculator.cpp
#include "scientific_calculator.h"
ScientificCalculator::ScientificCalculator() {}
double ScientificCalculator::power(double base, double exponent) {
return std::pow(base, exponent); // Uses the cmath library
}
double ScientificCalculator::squareRoot(double value) {
if (value < 0) {
throw std::invalid_argument("Cannot take square root of a negative number.");
}
return std::sqrt(value); // Uses the cmath library
}
ScientificCalculator::~ScientificCalculator() {}
src/main.cpp
// main.cpp
#include <iostream>
#include "calculator.h"
#include "scientific_calculator.h"
int main() {
Calculator calc; // Instance of base Calculator class
ScientificCalculator sciCalc; // Instance of derived ScientificCalculator class
int a = 10;
int b = 5;
std::cout << "Basic Calculator Operations:" << std::endl;
std::cout << "Addition: " << calc.add(a, b) << std::endl;
std::cout << "Subtraction: " << calc.subtract(a, b) << std::endl;
std::cout << "Multiplication: " << calc.multiply(a, b) << std::endl;
try {
std::cout << "Division: " << calc.divide(a, b) << std::endl;
} catch (const std::invalid_argument& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
std::cout << "\nScientific Calculator Operations:" << std::endl;
double base = 2.0;
double exponent = 3.0;
double value = 25.0;
std::cout << "Power (" << base << "^" << exponent << "): " << sciCalc.power(base, exponent) << std::endl;
try {
std::cout << "Square Root of " << value << ": " << sciCalc.squareRoot(value) << std::endl;
} catch (const std::invalid_argument& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
return 0;
}
Scientific Calculator, using classes + inheritance + polymorphism
We’ll introduce a virtual function in the Calculator class and add it in ScientificCalculator. This will allow us to use polymorphism to call the appropriate function based on the actual object type, even when using a base class pointer or reference.
What does this mean? If you’re using a pointer for an object (e.g. ScientificCalculator), and then pass it to a function expecting a base class type (e.g. performCalculation(Calculator* calc, double x, double y), the expected class type is “Calculator"), the function will invoke the derived class's overridden method instead of the base class's method.
The following example is stripped down to only include the virtual method.
include/calculator.h
// calculator.h
#ifndef CALCULATOR_H
#define CALCULATOR_H
class Calculator {
public:
Calculator();
// Virtual function for polymorphism
virtual double calculate(double a, double b); // Default: performs addition
// Destructor
virtual ~Calculator();
};
#endif // CALCULATOR_H
include/scientific_calculator.h
// scientific_calculator.h
#ifndef SCIENTIFIC_CALCULATOR_H
#define SCIENTIFIC_CALCULATOR_H
#include "calculator.h"
#include <cmath> // For pow function
class ScientificCalculator : public Calculator {
public:
ScientificCalculator();
// Redefine calculate function to perform exponentiation
double calculate(double base, double exponent);
~ScientificCalculator();
};
#endif // SCIENTIFIC_CALCULATOR_H
src/calculator.cpp
// calculator.cpp
#include "calculator.h"
Calculator::Calculator() {}
double Calculator::calculate(double a, double b) {
return a + b; // Default operation (addition)
}
Calculator::~Calculator() {}
src/scientific_calculator.cpp
// scientific_calculator.cpp
#include "scientific_calculator.h"
ScientificCalculator::ScientificCalculator() {}
double ScientificCalculator::calculate(double base, double exponent) {
return std::pow(base, exponent); // Performs base^exponent
}
ScientificCalculator::~ScientificCalculator() {}
src/main.cpp
// main.cpp
#include <iostream>
#include "calculator.h"
#include "scientific_calculator.h"
// Function to perform calculation via base class pointer
// This will call the right method even though the type is listed as "Calculator", due to the virtual function.
void performCalculation(Calculator* calc, double x, double y) {
std::cout << "Result of calculation: " << calc->calculate(x, y) << std::endl;
}
int main() {
Calculator basicCalc; // Basic calculator instance
ScientificCalculator sciCalc; // Scientific calculator instance
// Using a Calculator pointer to demonstrate polymorphism
Calculator* calcPtr = &basicCalc;
std::cout << "Using Calculator object:" << std::endl;
performCalculation(calcPtr, 5.0, 3.0); // Calls Calculator::calculate (addition)
calcPtr = &sciCalc;
std::cout << "Using ScientificCalculator object:" << std::endl;
performCalculation(calcPtr, 2.0, 3.0); // Calls ScientificCalculator::calculate (exponentiation)
return 0;
}