An open API service indexing awesome lists of open source software.

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++.

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. πŸš€