This project is part of the 42 C++ modules. The main goal of this module is to understand inheritance in C++ through a small robot hierarchy based on ClapTrap, ScavTrap, FragTrap, and DiamondTrap.
The project is written in C++98 and compiled with strict warning flags.
c++ -Wall -Wextra -Werror -std=c++98CPP Module 03 focuses on building classes that reuse and extend behavior from other classes. It starts with a basic class, ClapTrap, then introduces derived classes, construction and destruction order, multiple inheritance, and the diamond inheritance problem.
The exercises are organized in order:
ex00/ ClapTrap
ex01/ ScavTrap
ex02/ FragTrap
ex03/ DiamondTrap
Each exercise has its own directory and Makefile.
To build an exercise:
cd ex00
makeTo run the program:
./claptrapTo clean object files:
make cleanTo remove object files and the executable:
make fcleanTo rebuild everything:
make reThis project follows the main rules of the C++ modules:
- compiled with
c++ - uses
-Wall -Wextra -Werror - compatible with
-std=c++98 - does not use forbidden C functions such as
printf,malloc,calloc,realloc, orfree - does not use
using namespace std - does not use external libraries
- avoids STL containers and algorithms before the allowed modules
- keeps function implementations in
.cppfiles instead of header files - uses include guards in header files
The first exercise introduces a basic ClapTrap class. This class represents a simple robot with a name, hit points, energy points, and attack damage.
class ClapTrapThe class stores:
name: the robot's namehitPoints: the robot's healthenergyPoints: the robot's available energyattackDamage: the amount of damage caused by an attack
void attack(const std::string& target);
void takeDamage(unsigned int amount);
void beRepaired(unsigned int amount);In this exercise, I practiced how to design a basic C++ class with private or protected data and public behavior. I learned how an object can protect its internal state while exposing functions that safely modify that state.
I also practiced the Orthodox Canonical Form, which includes:
- default constructor
- copy constructor
- copy assignment operator
- destructor
This exercise also reinforced the idea that constructors and destructors are automatically called when objects are created and destroyed.
The class keeps its data inside itself and only allows controlled access through member functions. For example, hit points should not be changed directly from outside the class; they should be changed through functions such as takeDamage() or beRepaired().
The robot's behavior depends on its current state. If it has no hit points or no energy points, it cannot attack or repair itself.
The functions work on the current object. For example, attack() uses the current object's energy points and attack damage.
The second exercise introduces inheritance by creating a new class named ScavTrap, derived from ClapTrap.
class ScavTrap : public ClapTrapScavTrap reuses the base behavior of ClapTrap, but it has different initial values:
- hit points:
100 - energy points:
50 - attack damage:
20
It also has its own special ability:
void guardGate(void);In this exercise, I learned how a derived class can inherit data and behavior from a base class. ScavTrap is a specialized version of ClapTrap, so it can reuse common functions such as takeDamage() and beRepaired().
I also learned that constructing a derived object first constructs the base part, then the derived part. Destruction happens in the opposite order.
Inheritance allows a class to be built from another class. ScavTrap inherits from ClapTrap, which means a ScavTrap is a kind of ClapTrap.
ClapTrap is the base class. ScavTrap is the derived class. The base class provides shared behavior, while the derived class adds or changes behavior.
When a ScavTrap object is created, the ClapTrap constructor runs first. This makes sure the base part of the object exists before the derived part is initialized.
When a ScavTrap object is destroyed, the ScavTrap destructor runs first, then the ClapTrap destructor. This is the reverse of construction.
ScavTrap provides its own version of attack(). When calling attack() on a ScavTrap object, the ScavTrap version is used instead of the ClapTrap version.
The third exercise adds another derived class named FragTrap. Like ScavTrap, it inherits from ClapTrap, but it has different values and a different special ability.
class FragTrap : public ClapTrapFragTrap has these initial values:
- hit points:
100 - energy points:
100 - attack damage:
30
It also has its own special ability:
void highFivesGuys(void);In this exercise, I practiced creating another derived class from the same base class. This helped me understand how multiple derived classes can share common behavior while still having their own identity.
I also learned that inheritance helps reduce duplicated code. Since FragTrap and ScavTrap both share basic robot behavior, that shared logic can stay inside ClapTrap.
Instead of rewriting the same damage and repair logic in every class, the common logic is placed in ClapTrap. Derived classes can reuse it.
FragTrap is a more specific type of ClapTrap. It has its own stats and its own ability, while still keeping the base features of a ClapTrap.
Both ScavTrap and FragTrap depend on ClapTrap for common behavior. This makes the class hierarchy easier to maintain.
The final exercise introduces multiple inheritance and the diamond inheritance problem. DiamondTrap inherits from both FragTrap and ScavTrap.
class DiamondTrap : public FragTrap, public ScavTrapDiamondTrap combines features from both parent classes:
- hit points from
FragTrap - energy points from
ScavTrap - attack damage from
FragTrap attack()fromScavTrap
It also has its own name, while the ClapTrap base part has a different name ending with "_clap_name".
The class also implements:
void whoAmI(void);This function prints both the DiamondTrap name and the ClapTrap name.
In this exercise, I learned that multiple inheritance can be powerful but also dangerous. If two parent classes come from the same base class, the final class may accidentally contain two copies of the same base class.
This problem is called the diamond problem. To solve it, the project can use virtual inheritance, so the final object contains only one shared ClapTrap base part.
Multiple inheritance means one class inherits from more than one parent class. DiamondTrap inherits from both FragTrap and ScavTrap.
The diamond problem happens when a class inherits from two classes that both inherit from the same base class. In this project, both FragTrap and ScavTrap inherit from ClapTrap, and DiamondTrap inherits from both of them.
Without a solution, DiamondTrap may contain two separate ClapTrap parts, which can cause ambiguity.
Virtual inheritance is used to make sure that only one shared base class subobject exists. In this project, it can be used so that DiamondTrap contains only one ClapTrap base part.
Example:
class ScavTrap : virtual public ClapTrap
class FragTrap : virtual public ClapTrapDiamondTrap has its own name, while ClapTrap also has a name. These two names are different pieces of data. When two members have the same name, the more specific one can hide the other. To access the base class version clearly, scope resolution can be used.
The :: operator is used to specify exactly which class member should be used.
Example:
ClapTrap::name
ScavTrap::attack(target)This helps avoid confusion when several parent classes contain members with the same name.
CPP Module 03 helped me understand how C++ classes can be connected through inheritance. I learned how to build a base class, create derived classes, reuse common behavior, customize child classes, and deal with more complex inheritance structures.
The most important lesson from this module is that inheritance is useful for sharing behavior, but it must be designed carefully. Simple inheritance makes code easier to reuse, while multiple inheritance can create ambiguity if the class hierarchy is not clearly structured.