{"id":50338721,"url":"https://github.com/tigran-sargsyan-w/cpp-module-04","last_synced_at":"2026-05-29T15:30:27.041Z","repository":{"id":329744670,"uuid":"1119165559","full_name":"tigran-sargsyan-w/cpp-module-04","owner":"tigran-sargsyan-w","description":"This module is designed to help you understand subtype polymorphism, abstract classes, and interfaces in C++.","archived":false,"fork":false,"pushed_at":"2026-01-11T10:12:08.000Z","size":50,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-06T11:49:04.027Z","etag":null,"topics":["42","42-school","abstract-class","cpp","cpp-modules","cpp98","deep-copy","inheritance","interface","memory-management","object-oriented-programming","oop","polymorphism","pure-virtual","rule-of-three","subtype-polymorphism","virtual-functions"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tigran-sargsyan-w.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-18T21:12:05.000Z","updated_at":"2026-01-11T10:21:21.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/tigran-sargsyan-w/cpp-module-04","commit_stats":null,"previous_names":["tigran-sargsyan-w/cpp-module-04"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tigran-sargsyan-w/cpp-module-04","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tigran-sargsyan-w%2Fcpp-module-04","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tigran-sargsyan-w%2Fcpp-module-04/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tigran-sargsyan-w%2Fcpp-module-04/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tigran-sargsyan-w%2Fcpp-module-04/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tigran-sargsyan-w","download_url":"https://codeload.github.com/tigran-sargsyan-w/cpp-module-04/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tigran-sargsyan-w%2Fcpp-module-04/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33659872,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["42","42-school","abstract-class","cpp","cpp-modules","cpp98","deep-copy","inheritance","interface","memory-management","object-oriented-programming","oop","polymorphism","pure-virtual","rule-of-three","subtype-polymorphism","virtual-functions"],"created_at":"2026-05-29T15:30:21.389Z","updated_at":"2026-05-29T15:30:27.034Z","avatar_url":"https://github.com/tigran-sargsyan-w.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# C++ Module 04 – Subtype Polymorphism, Abstract Classes \u0026 Interfaces 🐾🧠🧊\n\n✅ **Status**: Completed – all exercises  \n🏫 **School**: 42 – C++ Modules (Module 04)  \n🏅 **Score**: 100/100\n\n\u003e *Subtype polymorphism, virtual functions, deep copies, abstract classes, and “interfaces” via pure abstract classes (C++98).*\n\n---\n\n## 📚 Table of Contents\n\n- [Description](#-description)\n- [Goals of the Module](#-goals-of-the-module)\n- [Concept Notes](#-concept-notes)\n  - [Why the base destructor must be virtual](#-why-the-base-destructor-must-be-virtual)\n  - [Deep copy vs shallow copy](#-deep-copy-vs-shallow-copy)\n  - [Abstract class vs interface in C++98](#-abstract-class-vs-interface-in-c98)\n  - [Why write `virtual` in derived classes? What about `override`?](#-why-write-virtual-in-derived-classes-what-about-override)\n- [Exercises Overview](#-exercises-overview)\n  - [ex00 – Polymorphism](#ex00--polymorphism)\n  - [ex01 – I don’t want to set the world on fire](#ex01--i-dont-want-to-set-the-world-on-fire)\n  - [ex02 – Abstract class](#ex02--abstract-class)\n  - [ex03 – Interface \u0026 recap](#ex03--interface--recap)\n- [Requirements](#-requirements)\n- [Build \u0026 Run](#-build--run)\n- [Repository Layout](#-repository-layout)\n- [Testing Tips](#-testing-tips)\n- [42 Notes](#-42-notes)\n\n---\n\n## 📝 Description\n\nThis repository contains my solutions to **42’s C++ Module 04 (C++98)**.\nThe module focuses on **runtime polymorphism** (virtual functions), **proper destruction through base pointers**, **deep-copy ownership** (Rule of Three), plus **abstract classes and interface-like design** using pure virtual methods.\n\n---\n\n## 🎯 Goals of the Module\n\nConcepts covered (depending on the exercise):\n\n- Subtype polymorphism: **virtual functions**, virtual dispatch, overriding\n- Correct destruction: **virtual destructors** when deleting through base pointers\n- Composition + ownership: `Brain*` inside `Dog` / `Cat` + proper `new/delete`\n- **Deep copy** vs shallow copy (copy constructor + assignment operator)\n- Abstract classes (non-instantiable base)\n- “Interfaces” via **pure abstract classes** (`= 0`)\n\n---\n\n## 🧩 Concept Notes\n\n### ✅ Why the base destructor must be virtual\n\nIf you ever delete an object through a **base pointer**, the base class **must** have a `virtual` destructor.\n\n```cpp\nAnimal* a = new Dog();\ndelete a; // must call ~Dog() then ~Animal()\n```\n\n* If `~Animal()` is **not virtual**, the program may call only `~Animal()`.\n* Result: derived cleanup is skipped → leaks (e.g. `Brain*`) and/or undefined behavior.\n\n✅ Practical rule:\n\n* **If a class is meant to be used polymorphically (has virtual methods), give it a virtual destructor.**\n\n---\n\n### 🧬 Deep copy vs shallow copy\n\nWhen a class owns heap memory (like `Brain*`), copying must be a **deep copy**.\n\n**Shallow copy (bad):** copies only the pointer.\n\n```cpp\nthis-\u003ebrain = other.brain; // ❌ both objects share the same Brain\n```\n\nProblems:\n\n* shared state (changing ideas in one changes the other)\n* double `delete` (crash)\n\n**Deep copy (good):** allocates a new resource and copies the content.\n\n```cpp\nthis-\u003ebrain = new Brain(*other.brain); // ✅ independent copy\n```\n\nThis is why ex01/ex02 naturally push you to the **Rule of Three**:\n\n* destructor\n* copy constructor\n* copy assignment operator\n\n---\n\n### 🧱 Abstract class vs interface in C++98\n\nIn C++98 we don’t have a special `interface` keyword — we build it using **pure abstract classes**.\n\n**Abstract class (common at 42):**\n\n* has at least one pure virtual method (`= 0`)\n* cannot be instantiated\n* may contain data and some shared implementation\n\n```cpp\nclass Animal {\npublic:\n    virtual ~Animal() {}\n    virtual void makeSound() const = 0; // pure\n};\n```\n\n**Interface-style class (ex03 style):**\n\n* usually *only* pure virtual methods\n* no data\n* always a virtual destructor\n\n```cpp\nclass ICharacter {\npublic:\n    virtual ~ICharacter() {}\n    virtual std::string const\u0026 getName() const = 0;\n    virtual void equip(AMateria* m) = 0;\n    virtual void unequip(int idx) = 0;\n    virtual void use(int idx, ICharacter\u0026 target) = 0;\n};\n```\n\n---\n\n### 🧷 Why write `virtual` in derived classes? What about `override`?\n\n**Key fact:** once a method is `virtual` in the base class, it stays virtual in all derived classes — even if you don’t repeat the word `virtual`.\n\n```cpp\nclass Animal { public: virtual void makeSound() const; };\nclass Dog : public Animal {\npublic:\n    void makeSound() const;        // ✅ still virtual (because Animal’s is virtual)\n    // virtual void makeSound() const; // ✅ optional, for readability\n};\n```\n\nSo why do people still write `virtual` again?\n\n* **Readability**: makes it obvious this method is part of polymorphism.\n* **Consistency** in headers.\n\nBut repeating `virtual` does *not* protect you from the most common bug:\n\n* **signature mismatch** (accidentally not overriding)\n\nExample:\n\n```cpp\nclass Animal { public: virtual void makeSound() const; };\nclass Dog : public Animal {\npublic:\n    void makeSound(); // ❌ not overriding (missing const) → creates a different function\n};\n```\n\nIn modern C++ (C++11+), you’d write:\n\n```cpp\nvoid makeSound() const override;\n```\n\nThat forces the compiler to error if it doesn’t actually override.\n\nIn **C++98**, `override` does not exist, so common alternatives are:\n\n* repeat the exact signature carefully (including `const`)\n* optionally write a comment:\n\n  ```cpp\n  virtual void makeSound() const; // override\n  ```\n\n---\n\n## 📦 Exercises Overview\n\n### ex00 – Polymorphism\n\n**Goal:**\nImplement a base class `Animal` with a `type` and a `makeSound()` method.\nCreate derived classes `Dog` and `Cat` that override `makeSound()` so calls through `Animal*` produce the *derived* sound.\n\nAlso implement `WrongAnimal` / `WrongCat` to demonstrate what happens when polymorphism is done “wrong” (e.g., missing `virtual`).\n\n**Concepts practiced:**\n\n* `virtual` functions and overriding\n* Polymorphic behavior via base pointers/references\n* Why forgetting `virtual` breaks dynamic dispatch\n\n---\n\n### ex01 – I don’t want to set the world on fire\n\n**Goal:**\nAdd a `Brain` class with `std::string ideas[100]`.\n`Dog` and `Cat` must own a `Brain*` and manage it with `new` / `delete`.\n\nIn `main`, create an array of `Animal*` (half dogs / half cats), then `delete` them via `Animal*` and ensure destructors are called correctly and there are **no leaks**.\n\nCopies of `Dog` and `Cat` must be **deep copies** (no shared Brain).\n\n**Concepts practiced:**\n\n* Rule of Three (copy ctor, assignment, destructor)\n* Deep copy ownership \u0026 avoiding double free / leaks\n* Polymorphic deletion order\n\n---\n\n### ex02 – Abstract class\n\n**Goal:**\nMake the base `Animal` **non-instantiable** (because an “Animal” doesn’t make sense by itself). Everything should still work as before with `Dog` / `Cat`.\n\n\u003e Optional: rename it to `AAnimal` (depending on your preference / implementation).\n\n**Concepts practiced:**\n\n* Pure virtual functions\n* Abstract base classes and intent in API design\n\n---\n\n### ex03 – Interface \u0026 recap\n\n**Goal:**\nImplement a small Materia system:\n\n* `AMateria` (abstract base): has `type`, `clone()` (pure virtual), and `use()`\n* Concrete materias: `Ice` and `Cure`\n\n  * `type`: `\"ice\"` / `\"cure\"`\n  * `clone()` returns a new instance of the same type\n* `ICharacter` interface + concrete `Character` with an inventory of **4 slots**\n\n  * `equip()` puts materia into the first empty slot\n  * `unequip()` must **not delete** materia\n  * copies of `Character` must be **deep** (inventory cloned, old deleted)\n* `IMateriaSource` interface + `MateriaSource`\n\n  * can learn up to **4** materia “templates” (store copies)\n  * can `createMateria(type)` by cloning learned template, or return `0` if unknown\n\n**Important note:**\nUnequipped materias must still be managed somehow (save addresses, “floor” storage, etc.) to avoid leaks.\n\n**Concepts practiced:**\n\n* Interface design in C++98 (pure abstract classes)\n* Cloning pattern / prototype pattern\n* Ownership rules and memory safety\n\n---\n\n## 🛠 Requirements\n\nFrom the subject:\n\n* **Compiler**: `c++`\n* **Flags**: `-Wall -Wextra -Werror` (and it must compile with `-std=c++98`)\n* **No external libraries**\n* Forbidden: `printf`, `malloc`, `free` (and family)\n* Until later modules: **no STL containers / algorithms** (no `\u003cvector\u003e`, no `\u003calgorithm\u003e`, etc.)\n* “Goodbye Norminette!” (no enforced C norm), but code must stay readable\n\n---\n\n## ▶️ Build \u0026 Run\n\n```bash\ngit clone \u003cthis-repo-url\u003e\ncd cpp-module-04\n```\n\n### ex00\n\n```bash\ncd ex00\nmake\n./animal\n```\n\n### ex01\n\n```bash\ncd ex01\nmake\n./animal\n```\n\n### ex02\n\n```bash\ncd ex02\nmake\n./animal\n```\n\n### ex03\n\n```bash\ncd ex03\nmake\n./interface\n```\n\n\u003e Executable names may vary depending on your Makefiles.\n\n---\n\n## 📂 Repository Layout\n\n```text\ncpp-module-04/\n├── ex00/\n│   ├── Makefile\n│   ├── main.cpp\n│   ├── Animal.hpp / Animal.cpp\n│   ├── Dog.hpp / Dog.cpp\n│   ├── Cat.hpp / Cat.cpp\n│   ├── WrongAnimal.hpp / WrongAnimal.cpp\n│   └── WrongCat.hpp / WrongCat.cpp\n│\n├── ex01/\n│   ├── Makefile\n│   ├── main.cpp\n│   ├── Animal.*  Dog.*  Cat.*\n│   └── Brain.hpp / Brain.cpp\n│\n├── ex02/\n│   ├── Makefile\n│   ├── main.cpp\n│   ├── AAnimal/Animal.*  Dog.*  Cat.*  Brain.*\n│   └── (same structure as ex01, but base is abstract)\n│\n└── ex03/\n    ├── Makefile\n    ├── main.cpp\n    ├── AMateria.*   Ice.*   Cure.*\n    ├── ICharacter.hpp   Character.*\n    ├── IMateriaSource.hpp  MateriaSource.*\n    └── (optional) Floor/Trash manager files\n```\n\n---\n\n## 🔍 Testing Tips\n\n* **ex00**\n\n  * Call `makeSound()` through `Animal*` and verify the derived sound is used\n  * Verify `WrongCat` behaves like `WrongAnimal` when polymorphism is broken\n\n* **ex01 / ex02**\n\n  * Copy a `Dog`/`Cat`, modify ideas in one Brain → the other must not change (deep copy)\n  * Run leak checks (example):\n\n    ```bash\n    valgrind --leak-check=full ./animal\n    ```\n  * Ensure destructors are called in correct order when deleting through `Animal*`\n\n* **ex03**\n\n  * Test inventory boundaries (equip 5th materia → nothing happens)\n  * Test `unequip()` does not delete; ensure you still free unequipped materias later\n  * Copy a `Character` and confirm deep copy (materias cloned; originals independent)\n  * `MateriaSource` creates only known types; unknown → returns `0`\n\n---\n\n## 🧾 42 Notes\n\n* Outputs from constructors/destructors should be **distinct per class** to make tests readable.\n* This module is heavily about **ownership rules** — if you `new`, you must `delete` exactly once.\n* You can pass the module without ex03, but doing it is excellent practice for interfaces + memory management.\n\n---\n\nIf you’re a 42 student working on the same module: get inspired, but **write your own implementation** — that’s where the learning happens. 🚀\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftigran-sargsyan-w%2Fcpp-module-04","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftigran-sargsyan-w%2Fcpp-module-04","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftigran-sargsyan-w%2Fcpp-module-04/lists"}