https://github.com/tigran-sargsyan-w/cpp-module-03
This module is designed to help you understand inheritance in C++.
https://github.com/tigran-sargsyan-w/cpp-module-03
42 42-school claptrap class-design constructors cpp cpp98 destructors diamond-problem diamondtrap fragtrap inheritance multiple-inheritance oop orthodox-canonical-class polymorphism scavtrap
Last synced: 10 days ago
JSON representation
This module is designed to help you understand inheritance in C++.
- Host: GitHub
- URL: https://github.com/tigran-sargsyan-w/cpp-module-03
- Owner: tigran-sargsyan-w
- Created: 2025-12-17T16:41:27.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2025-12-23T20:49:33.000Z (6 months ago)
- Last Synced: 2026-05-06T11:49:04.027Z (about 1 month ago)
- Topics: 42, 42-school, claptrap, class-design, constructors, cpp, cpp98, destructors, diamond-problem, diamondtrap, fragtrap, inheritance, multiple-inheritance, oop, orthodox-canonical-class, polymorphism, scavtrap
- Language: C++
- Homepage:
- Size: 45.9 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# C++ Module 03 β Inheritance & Diamond Problem π§¬π
β
**Status**: Completed β all exercises
π« **School**: 42 β C++ Modules (Module 03)
π
**Score**: 100/100
> *Single inheritance, multiple inheritance, method overriding, base/derived behavior, and the classic βdiamondβ problem.*
---
## π Table of Contents
* [Description](#-description)
* [Goals of the Module](#-goals-of-the-module)
* [Exercises Overview](#-exercises-overview)
* [ex00 β ClapTrap](#ex00--claptrap)
* [ex01 β ScavTrap](#ex01--scavtrap)
* [ex02 β FragTrap](#ex02--fragtrap)
* [ex03 β DiamondTrap](#ex03--diamondtrap)
* [Requirements](#-requirements)
* [Build & Run](#-build--run)
* [Repository Layout](#-repository-layout)
* [Testing Tips](#-testing-tips)
* [Quick Cheat Sheets](#-quick-cheat-sheets)
* [C++ Inheritance Modes](#c-inheritance-modes--quick-cheat-sheet)
* [C++ OOP Keywords](#c-oop-keywords-inheritance--polymorphism--quick-cheat-sheet)
* [42 Notes](#-42-notes)
---
## π Description
This repository contains my solutions to **42βs C++ Module 03 (C++98)**.
The module focuses on **inheritance** and how base/derived classes interact:
* Single inheritance (`ClapTrap` β `ScavTrap` / `FragTrap`)
* Overriding behavior (e.g., redefining `attack()` in derived classes)
* Understanding constructor/destructor order
* Multiple inheritance and the **diamond problem** (`DiamondTrap`)
* Sharing a single base with **virtual inheritance**
All exercises are written in **C++98** and compiled with strict flags (`-Wall -Wextra -Werror -std=c++98`).
---
## π― Goals of the Module
Concepts practiced in this module:
* **Inheritance** (`public` inheritance for βis-aβ)
* **Overriding** methods and calling base implementations when needed
* **Constructor initialization lists** in an inheritance chain
* **Rule of Three** (copy constructor, assignment operator, destructor)
* **Multiple inheritance** and resolving ambiguity
* **Virtual inheritance** to solve the βdiamondβ (single shared base)
---
## π¦ Exercises Overview
### ex00 β ClapTrap
> A small combat-style class used as a base for the rest of the module.
**Goal:**
Implement `ClapTrap` with the canonical behavior:
* `attack(target)` consumes energy and prints an action
* `takeDamage(amount)` decreases hit points
* `beRepaired(amount)` consumes energy and restores hit points
**Concepts practiced:**
* Basic class design
* State management (HP/EP/AD)
* Copy / assignment / destructor (Rule of Three)
---
### ex01 β ScavTrap
> First derived class: specialized behavior + custom stats.
**Goal:**
Create `ScavTrap` inheriting from `ClapTrap`, with:
* Updated default stats (HP/EP/AD according to the subject)
* Overridden `attack()` (ScavTrap-style message)
* New ability: `guardGate()`
**Concepts practiced:**
* `public` inheritance and overriding
* Derived class constructors calling base constructors
---
### ex02 β FragTrap
> Second derived class: high energy, friendly vibes.
**Goal:**
Create `FragTrap` inheriting from `ClapTrap`, with:
* Updated default stats (HP/EP/AD)
* New ability: `highFivesGuys()`
**Concepts practiced:**
* More inheritance practice
* Consistent canonical form across classes
---
### ex03 β DiamondTrap
> Multiple inheritance + the βdiamondβ problem.
**Goal:**
Create `DiamondTrap` inheriting from both `FragTrap` and `ScavTrap`, while:
* Keeping **one** shared `ClapTrap` base (via **virtual inheritance**)
* Having its own `name` (DiamondTrap identity)
* Storing the base name as `DiamondTrapName_clap_name`
* Using `ScavTrap::attack()`
* Adding `whoAmI()` to print both names:
* DiamondTrapβs own name
* ClapTrapβs name
**Concepts practiced:**
* Multiple inheritance
* Ambiguity resolution (`Base::method()`)
* `virtual public Base` to ensure a single shared base
---
## π Requirements
From the subject (typical for 42 C++ modules):
* **Compiler**: `c++`
* **Flags**:
* `-Wall -Wextra -Werror`
* `-std=c++98`
* **OS**: any Unix-like system (Linux / macOS)
* **No external libraries** (no C++11+)
---
## βΆοΈ Build & Run
Clone the repository and build each exercise separately.
```bash
git clone
cd cpp-module-03
```
### ex00 β ClapTrap
```bash
cd ex00
make
./claptrap
```
### ex01 β ScavTrap
```bash
cd ex01
make
./scavtrap
```
### ex02 β FragTrap
```bash
cd ex02
make
./fragtrap
```
### ex03 β DiamondTrap
```bash
cd ex03
make
./diamondtrap
```
> Executable names may differ depending on your Makefiles / implementation.
---
## π Repository Layout
```text
cpp-module-03/
βββ ex00/
β βββ Makefile
β βββ ClapTrap.hpp
β βββ ClapTrap.cpp
β βββ main.cpp
β
βββ ex01/
β βββ Makefile
β βββ ClapTrap.hpp / ClapTrap.cpp
β βββ ScavTrap.hpp / ScavTrap.cpp
β βββ main.cpp
β
βββ ex02/
β βββ Makefile
β βββ ClapTrap.hpp / ClapTrap.cpp
β βββ FragTrap.hpp / FragTrap.cpp
β βββ main.cpp
β
βββ ex03/
βββ Makefile
βββ ClapTrap.hpp / ClapTrap.cpp
βββ ScavTrap.hpp / ScavTrap.cpp
βββ FragTrap.hpp / FragTrap.cpp
βββ DiamondTrap.hpp / DiamondTrap.cpp
βββ main.cpp
```
---
## π Testing Tips
### General
* Check that **HP/EP/AD** values match the subject defaults in each class.
* Verify that **energy can run out** and actions stop when EP = 0.
* Verify that **dead traps** (HP = 0) cannot attack/repair.
### ex03 (DiamondTrap)
* Confirm `ClapTrap` constructor is called **once** (shared base).
* Confirm `DiamondTrap::attack()` uses **ScavTrap-style** output.
* Confirm `whoAmI()` prints:
* `DiamondTrap name: Ruby`
* `ClapTrap name: Ruby_clap_name`
* Confirm destructor order is reasonable (derived β bases, virtual base last).
---
## π§ Quick Cheat Sheets
## C++ Inheritance Modes β Quick Cheat Sheet
**Mental model:**
* `Human` = base class
* `Warrior` = derived class
---
### 1) `public` β **βWarrior IS a Humanβ** β
```cpp
class Warrior : public Human {};
```
#### β
What works (outside code)
```cpp
void greet(Human& h);
Warrior w;
greet(w); // β
OK (is-a)
Human* p = &w; // β
OK
Human& r = w; // β
OK
```
#### π§ When to use
* Classic OOP **is-a** relationship
* Typical for school exercises (`ScavTrap` is-a `ClapTrap`)
---
### 2) `protected` β **βOutside: NOT Human, but for subclasses: yesβ**
```cpp
class Warrior : protected Human {};
```
#### β Forbidden (outside code)
```cpp
void greet(Human& h);
Warrior w;
greet(w); // β ERROR (outside canβt treat Warrior as Human)
Human* p = &w; // β ERROR
Human& r = w; // β ERROR
```
#### β
What you *can* do
#### 1) Use `Warrior` as its own type
```cpp
void train(Warrior& w);
Warrior w;
train(w); // β
OK
```
#### 2) Inside `Warrior` you can access base members
```cpp
class Warrior : protected Human
{
public:
void demo()
{
attack(); // β
if attack() was public/protected in Human
hitPoints = 10; // β
if hitPoints was protected in Human
}
};
```
#### 3) Inside a subclass of `Warrior` you can still access base members
```cpp
class EliteWarrior : public Warrior
{
public:
void demo()
{
attack(); // β
base is visible as protected
hitPoints = 99; // β
if it was protected in Human
}
};
```
### π§ When to use
* Rare
* You want to **hide βis-aβ from outside**, but but keep the base accessible for subclasses.
---
### 3) `private` β **βWarrior is NOT Human; it just uses Human internallyβ** π
```cpp
class Warrior : private Human {};
// For `class`, this is the default:
class Warrior : Human {}; // β private inheritance by default
```
#### β Forbidden (outside code)
```cpp
void greet(Human& h);
Warrior w;
greet(w); // β ERROR
Human* p = &w; // β ERROR
Human& r = w; // β ERROR
```
#### β Forbidden (even for subclasses of `Warrior`)
```cpp
class EliteWarrior : public Warrior
{
public:
void demo()
{
attack(); // β ERROR (Human part became private inside Warrior)
hitPoints = 99; // β ERROR
}
};
```
### β
What you *can* do
#### 1) Inside `Warrior` you can use the base (implementation detail)
```cpp
class Warrior : private Human
{
public:
void demo()
{
attack(); // β
OK inside Warrior
hitPoints = 10; // β
if protected in Human
}
};
```
#### 2) Expose only what you want (wrapper / selective re-export)
```cpp
class Warrior : private Human
{
public:
using Human::attack; // β
make only this base method public
void specialMove();
};
```
Or forward manually:
```cpp
class Warrior : private Human
{
public:
void attackPublic(const std::string& target)
{
attack(target); // β
call base inside
}
};
```
### π§ When to use
* Rare (often composition is better)
* When inheritance is **only for code reuse**, not for βis-aβ
---
### Default rule (VERY IMPORTANT) β οΈ
```cpp
class A : B {}; // = private inheritance (default)
struct A : B {}; // = public inheritance (default)
```
---
### Ultra-short summary
* `public` β **IS-A**
* `protected` β **IS-A only for subclasses**
* `private` β **implementation detail (code reuse), not IS-A**
---
## C++ OOP Keywords (Inheritance & Polymorphism) β Quick Cheat Sheet
> A compact list of keywords/idioms that matter most around inheritance.
---
### 1) `virtual` (methods) β **polymorphism** π
If a base method is `virtual`, a call through `Base&` / `Base*` will dispatch to the derived override.
```cpp
class Base {
public:
virtual void speak();
};
class Der : public Base {
public:
void speak() override;
};
```
**Why:** βone interface β multiple implementationsβ.
---
### 2) `override` β **compile-time check that you really override** β
```cpp
void speak() override;
```
If the signature doesnβt match exactly (params, `const`, refs, etc.), you get a compile error.
---
### 3) `final` β **prevent inheritance / prevent further overrides** π§±
#### Class canβt be inherited:
```cpp
class Boss final {};
```
#### Method canβt be overridden further:
```cpp
class Base {
public:
virtual void speak() final;
};
```
---
### 4) `virtual` destructor β **safe delete via base pointer** π§¨
If you have polymorphism (virtual methods) and you might do `delete basePtr;`, the base destructor should almost always be `virtual`.
```cpp
class Base {
public:
virtual ~Base();
};
class Der : public Base {
public:
~Der();
};
Base* p = new Der();
delete p; // β
calls ~Der(), then ~Base()
```
Without `virtual ~Base()` you risk only `~Base()` being called.
---
### 5) `protected` β **visible to derived classes, hidden from outside** π‘οΈ
```cpp
class Base {
protected:
int hp;
};
```
**Idea:** derived classes can access it; external code cannot.
---
### 6) `using Base::method;` β **keep overloads visible / selectively re-export** π
A derived method with the same name can hide base overloads (name hiding).
```cpp
class Base {
public:
void attack(int);
void attack(double);
};
class Der : public Base {
public:
using Base::attack; // β
bring base overloads back into scope
void attack(const char*);
};
```
Also handy with `private` inheritance: you can expose only specific base methods.
---
### 7) `explicit` (constructors) β **block implicit conversions** π«
```cpp
class Money {
public:
explicit Money(int cents);
};
Money m = 42; // β not allowed
Money m2(42); // β
allowed
```
---
### 8) `= delete` / `= default` β **control copy/assignment** π§°
```cpp
class Base {
public:
Base() = default;
Base(const Base&) = delete;
Base& operator=(const Base&) = delete;
virtual ~Base() = default;
};
```
**Why:** some bases must not be copyable (resources, ownership, etc.).
---
### 9) `Base::method()` β **explicitly call the base version** π―
Useful with overriding / multiple inheritance.
```cpp
void Der::attack(const std::string& target)
{
Base::attack(target); // call base implementation
}
```
---
### Tiny reminder: `virtual` has 2 different meanings in C++ β οΈ
* `virtual` **on methods** β polymorphism (`override` / `final`)
* `virtual` **in inheritance** (`class A : virtual public B`) β a single shared base in the βdiamondβ
---
## π§Ύ 42 Notes
* C++ modules at 42 generally target **C++98** (no modern features unless explicitly allowed).
* There is no Norminette for C++, but clean structure and readable output logs help a lot during evaluation.
* If your logs differ slightly, check:
* Constructor/destructor order
* Which class version of `attack()` is being called
* Whether your base is truly shared in the diamond (`virtual public ClapTrap`)
---
If youβre a 42 student working on the same module: feel free to explore, get inspired, but **write your own implementation** β thatβs where the learning happens. π