Skip to content

alcarril/Cpps

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

400 500

C++ Modules

This repository contains solutions for the 42 school C++ modules (Cpp00 - Cpp09).

Build

Each exercise contains a Makefile. To compile an exercise:

cd CppXX/exXX
make

Makefile targets

make | make all    - Compile the program
make clean        - Remove object files
make fclean       - Remove object files and executable
make re           - Recompile everything
make debug        - Clean rebuild with debug flags (address sanitizer)

Requirements

C++ compiler (c++)
C++98 standard
Make

MODULES

Each module includes exercise links and a cheat-sheet section of the C++ concepts used in that module.

Cpp00

Introduction to C++ basics: namespaces, classes, member functions, stdio streams, initialization lists, static, const, and some other basic stuff.

Exercises

Generic concepts
  • Class concept
  • Object concept
  • Abstraction and encapsulation
  • Public and private attributes
  • What are references
  • Basic use of streams and classes from the std namespace
  • Use of string objects
  • Scope operators for class method definitions from another file
  • What are constructors and initialization lists
  • Use of the this clause
  • Use of static attributes and the concept of not belonging to any object
  • Static methods, which are the only ones that can modify static variables
  • Arrays of objects
  • Basic composition concept

Cpp01

Memory allocation, pointers to members, references, switch statement.

Exercises

Generic concepts
  • Dynamic memory allocation with new
  • Destroying dynamic memory with delete
  • Arrays of objects with default constructor
  • Class destructor concept
  • Using stringstream to simulate base changes
  • Concept of references and differences with pointers
  • References passed as parameters to avoid memory duplication
  • Pointers to point to objects from an external object without owning them
  • References to point to external objects but associated with the class itself
  • Using fstream class and string class method to convert to char *
  • getline function
  • Function pointers and arrays of function pointers (notations)
  • Use of switch (internally uses jump tables or binary trees to keep O(1) complexity)

Cpp02

Ad-hoc polymorphism, operator overloading, and Orthodox Canonical class Form.

Exercises

Generic concepts
  • What are fixed point numbers and why are they used for determinism across different processor architectures regardless of FPU presence
  • How they are created with bit shifting and how operations are performed with fixed point numbers
  • Construction of orthodox canonical classes (default constructor, copy constructor, default destructor, and overloaded assignment operator to avoid bitwise copy or shallow copy)
  • Compile-time polymorphism or ad-hoc polymorphism
  • Overloaded operators for direct arithmetic and logical operations between objects
  • Overloading operator for ofstream object to print to screen/stdout redirections
  • Overloaded operators for post-increment and pre-increment operations on numbers
  • Why you should return objects directly in overloaded arithmetic operations but return references in assignment operations (+=, -=, etc.)

Cpp03

Inheritance in C++.

Exercises

Generic concepts
  • Inheritance
  • Inheritance of public, protected, and private attributes
  • No inheritance of overloaded operators, constructors, and destructors
  • Memory of the base class and the derived class
  • Destruction order of an object built through a base class
  • What is the virtual table and why it enables polymorphism
  • Why base class destructors should be virtual to avoid memory leaks in polymorphism
  • Calling base class constructors from the derived class to build the base part
  • Avoid calling base class constructors from derived classes if the base has a default constructor
  • Dynamic vs static polymorphism (concept)
  • Memory overhead due to the virtual table
  • What is object slicing
  • Using pointers and references to the base class for virtual method polymorphism in function parameters and class methods
  • What is object slicing and why you can't assign a derived object to a base object
  • Inheritance as specialization and composition for scalable class systems
  • Diamond classes and why you must inherit from the base class virtually to avoid duplicating the base part in the diamond class
  • Diamond class constructors must call the base class constructor

Cpp04

Subtype polymorphism, abstract classes and interfaces.

Exercises

Generic concepts
  • Polymorphism and memory scopes in polymorphism
  • Attribute hiding (shadowing)
  • Array of references notations in function parameters and return types
  • Shallow copy vs deep copy for dynamic memory
  • Abstract classes (non-instantiable but serve as base for polymorphism)
  • Interfaces or pure abstract classes
  • Non-constructible: serve as base for pointers and references in polymorphism
  • Class composition and circular dependencies
  • Const references as return values in getters to save memory and ensure attribute encapsulation

Cpp05

Exceptions.

Exercises

Generic concepts
  • How try, throw, and catch clauses work.
  • Types of data that can be thrown with throw, the std::exception class, and why it is recommended to throw objects.
  • What happens when an exception is thrown but not caught: (segfault) → std::terminate()
  • Memory scope of the try block: Objects created inside a try block have a local memory scope. When exiting the block due to an exception or normal execution, stack unwinding occurs, automatically destroying local objects. To preserve them, use pointers and dynamic memory.
  • Classes inheriting from std::exception and types of errors.
  • How to configure custom exceptions within classes by creating nested classes that inherit from std::exception and overriding the what() method for polymorphism. Why it is not a good idea to convert a normal class into an exception.
  • Why methods overriding std::exception methods should use the throw() clause to specify that the method will not throw another exception.
  • Nested classes are not constructed by default when using the constructor of the external class. They must be initialized in methods. Principles of nested class usage: Cohesion Principle and Single Responsibility.
Best Practices
  • Constructors that may throw errors due to invalid attribute values should only throw the error. The try and catch should be handled in main to avoid partially created objects in memory, which could lead to segmentation faults or undefined behavior.
  • Methods can have their own try and catch blocks for cleaner code.
  • Nested try blocks are possible but not clean. If an exception is thrown in the outer try, the inner block will not execute, and exceptions will not be lost.
  • When a base class defines its own errors and has methods overridden with polymorphism in derived classes, it is good practice to:
    • Throw base class errors from the base class methods.
    • In derived class methods, call the base class method to check for base errors, then handle specific errors in the derived class.
    • Throw different types of objects for different errors to avoid confusion in catch blocks.
  • When functions or methods with try blocks call other functions or methods with their own try blocks, exceptions thrown in the lower-level function may be caught there, causing the higher-level code to not behave as expected. In such cases, it is important that the try and catch blocks are always in the higher-level function, while the lower-level function should only contain throw statements ot throw objects of different types for different errors.

Cpp06

C++ casts and static_assert.

Exercises

Generic concepts
  • Types of casts in C++: reinterpret_cast, static_cast, dynamic_cast, and const_cast
    • static_cast:
      • Used for safe conversions between compatible types.
      • Respects strict aliasing rules.
      • Useful for upcasting and downcasting in class hierarchies without virtual functions.
    • reinterpret_cast:
      • Reinterprets the bits of memory regions.
      • Does not respect type compatibility and breaks strict aliasing rules.
      • Used for:
        • Conversions between pointers of different class types.
        • Serialization.
        • Systems programming.
        • Accessing memory-mapped regions.
        • Drivers.
        • Bootloaders.
        • Embedded systems.
    • dynamic_cast:
      • Runtime type casting.
      • Used for polymorphic class hierarchies with virtual functions.
      • Behavior:
        • For pointers: Performs downcasting and returns nullptr if the cast fails.
        • For references: Throws exceptions of type std::bad_cast (derived from std::exception) if the cast fails.
  • Serialization and deserialization: standardization across different systems
  • Why uintptr_t can be used to represent pointers (void*): portability across systems with different architectures, serialization of types
  • Methods for converting char* to numeric types and parsing:
    • std::stringstream from <sstream>
    • atoi, atol, and atof from <cstdlib>
    • strtol, strtoll, and strtod from <cstdlib>
  • is functions in C++ from <cctype>, <cmath>, and <cfloat>
  • limits functions from <climits> and <limits>
  • Base conversions
  • How to generate random numbers (seed + sequence)

Cpp07

Templates and iterators.

Exercises

Generic concepts
  • What are templates in C++ and why they are used
  • Templates and type deduction:
    • Function parameter templates:
      • Templates with multiple function parameters.
      • Templates with constant values and constant types.
      • Specialized templates (specialized data types).
    • Function templates (callbacks):
      • Explicit declaration: function type (return and arguments are data types or the template).
      • Implicit declaration (generic).
      • Calling a template function with an argument that is not another template function (template callbacks).
    • Memory address templates:
      • When a generic data template allows memory addresses to be passed (cannot dereference inside the template function).
      • When the template declaration specifies that the generic type is a pointer function(T* ptr), dereferencing is allowed, but the compiler only accepts pointers.
      • It is also possible to specify in the template function declaration that it is a reference or a pointer to a reference.
    • Const data templates (const-correctness):
      • When passing a generic data type (by value) to a template, it does not matter if the template parameter is const or not, or if the argument is const or not. The compiler allows both, because a copy is made and type compatibility is ensured.
      • When passing by reference, if the template is a non-const reference (e.g., T&) and the argument is const, there will be a type compatibility conflict and the compiler will give an error. If the template is a const reference (e.g., const T&), it accepts const, non-const, and temporaries without conflict.
      • When the template parameter is a pointer (e.g., T*), passing a const or non-const pointer is allowed; the compiler will add const to the type if needed for compatibility. You can also use const T* in the template to ensure the pointer cannot modify the value it points to inside the function, or use T* const to ensure the pointer itself cannot change the address it points to.
  • Class templates:
    • How to create a class template.
    • Method declarations must be in the .h file.
    • Methods that return a template-type object can be declared with return type Object& or Object<templatealias>&.
    • When instantiating a template-type object, it must be instantiated with ObjectName<datatype> alias(constructor).
    • When we want the template object to have its generic elements as const, it must be declared as const ObjectName<datatype> alias(constructor).
  • Overloading the array index access operator within objects.
  • Class hierarchy for inheritance: std::out_of_range.

Cpp08

STL (Standard Template Library), iterators and some algorithms.

Generic Container Concepts
  • Iterators:

    • Iterators are nested objects that contain an attribute which is a pointer to the internal positions of the container's data structure.
    • To instantiate them, you must use the object's scope operator: Object::iterator iterator_name;.
    • They are used to traverse containers and reference internal positions within the container.
    • Containers have the methods begin() and end(), which return an iterator pointing respectively to the first position of the container and to the position just after the last element of the container.
    • In practice, they are used like pointers, since they are objects overloaded with ad-hoc polymorphism. Their main operations are: it++, it--, ++it, --it, *it to access the value, it gives the memory address of the iterator object, &(*it) gives the memory address of the content pointed to by the iterator, and they support comparison and equality operations (<, >, >=, <=, ==).
    • When used in template functions (in the return type or function body), you must always use the typename T::iterator clause for the iterator, but you do not need to specify it in the function argument if the template expects to receive iterators (type deduction).
    • Iterators are used to create template functions that can traverse containers regardless of their type and perform generic operations on them; most functions in the <algorithm> library are based on this principle. This makes them valid for most containers that have iterators, such as std::vector, std::list, std::deque, std::set, std::map, etc.
    • When specializing a class by adding a nested iterator class, you should create the iterator using the iterator type of the internal container used by your class. If you don't know the exact type, you can use the pattern typename ContainerType::iterator to deduce it. For associative or specialized containers, you can use typename ContainerType::container_type::iterator to access the iterator type of the underlying container.
  • Containers:

    • Tipos de contenedores: secuenciales, asociativos, asociación.
    • Métodos de los contenedores genéricos y métodos específicos de los contenedores.
    • Formas de construir los contenedores según su tipo.
    • Firmas de acceso a los contenedores (iteradores, acceso aleatorio mediante operadores de sobrecarga y mediante métodos específicos).
    • Funcionamiento interno de los operadores de sobrecarga de los contenedores.
  • Algoritmos de la STL: std::sort, std::find, std::count, std::count_if, std::distance, std::advance, std::next, std::prev, std::min_element, std::max_element, adjacent_find`, etc.

Cpp09

STL containers, parsing, and algorithmic complexity.

Exercises

Generic concepts
  • Parsing structured text (CSV/space-delimited) with robust validation
    • Advanced use of std::string and std::stringstream for parsing-oriented workflows
    • Advanced casts and ctype functions for parsing checks and validations
  • Choosing containers per exercise based on use case and performance optimizations
    • Using associative containers (std::map) for lookups and ordered traversal
    • Stack-based evaluation for expressions (RPN)
    • Using sequential containers (std::vector, std::deque) for sorting and dynamic resizing
  • Algorithmic complexity: comparing container performance and scaling
  • Hybrid merge-insert sort and timing comparisons across containers
  • Iterator usage and range-based operations with the STL

Resources

Author 👨‍💻

alcarril - https://github.com/alcarril

Releases

No releases published

Packages

 
 
 

Contributors