⚙️ C++

POO: Encapsulamento e Polimorfismo em C++: Guia Detalhado

What is it and why? (real-life analogy)

Imagine you're assembling a robot vacuum cleaner. It has three main parts:

  • Motor — it spins the brushes and creates suction.
  • Sensors — they see walls and furniture.
  • Battery — provides energy.

When you press the "Start" button, you don't think: "Now I'll apply 12 volts to the motor windings, start the PWM controller, and poll the ultrasonic rangefinder." You just say: "Clean the room." Complex magic happens inside the robot, but on the outside — a simple interface.

It's the same in programming. Encapsulation is when we hide complex details inside an object and show only what's needed. Like a TV remote: you press the volume button, you don't go inside with a soldering iron.

Polymorphism is when the same interface works differently depending on the situation. Imagine you have a universal remote. If you point it at the TV — it changes channels. If at the air conditioner — it changes the temperature. The "On" button is the same, but the result is different.

💡 Remember: Encapsulation is about "what's inside is none of your business." Polymorphism is about "one interface — many implementations."

Theory: how it works internally

Encapsulation

In C++, encapsulation is implemented through access modifiers:

  • private — data is visible only inside the class. No one outside can touch it.
  • protected — data is visible inside the class and its descendants.
  • public — data is visible to everyone.

Best practice: make all fields (variables) private, and access them through public methods (getters and setters).

Polymorphism

Polymorphism comes in two types:

  1. Static (early binding) — resolved at compile time. This includes function overloading and templates.
  2. Dynamic (late binding) — resolved during program execution. Used through virtual functions and inheritance.

When you call a method on an object, the compiler checks: "Which exact method should I call?" If the method is virtual — the decision is postponed until program runtime.

⚠️ Important: Without virtual functions, polymorphism doesn't work in C++. If you forget to write virtual, the parent class method will be called, even if you passed a descendant object.

Syntax in C++: all forms and variants

Encapsulation: basic syntax

class RobotVacuum {
private:
    int chargeLevel;  // Hidden field — no one can change it directly
    bool isOn;

public:
    // Constructor — create an object
    RobotVacuum() {
        chargeLevel = 100;
        isOn = false;
    }

    // Getter — get the value
    int getCharge() {
        return chargeLevel;
    }

    // Setter — set the value with validation
    void setCharge(int newCharge) {
        if (newCharge >= 0 && newCharge <= 100) {
            chargeLevel = newCharge;
        }
    }

    // Public method — interface
    void pressStart() {
        if (chargeLevel > 10) {
            isOn = true;
            cout << "Robot started cleaning!" << endl;
        } else {
            cout << "Charge me!" << endl;
        }
    }
};

Polymorphism: virtual functions

class Animal {
public:
    // Virtual method — polymorphism
    virtual void makeSound() {
        cout << "Some animal makes a sound" << endl;
    }
};

class Dog : public Animal {
public:
    void makeSound() override {  // override — checks that the method is indeed virtual
        cout << "Woof-woof!" << endl;
    }
};

class Cat : public Animal {
public:
    void makeSound() override {
        cout << "Meow!" << endl;
    }
};

Access modifiers table

Modifier Inside class In descendant Outside
private ✅ Yes ❌ No ❌ No
protected ✅ Yes ✅ Yes ❌ No
public ✅ Yes ✅ Yes ✅ Yes

Code examples — from simple to complex

Example 1: Simplest encapsulation

#include <iostream>
using namespace std;

class Counter {
private:
    int value;  // Hidden field

public:
    // Constructor
    Counter() {
        value = 0;
    }

    // Method to increment
    void increment() {
        value++;
    }

    // Method to get the value
    int getValue() {
        return value;
    }
};

int main() {
    Counter myCounter;
    myCounter.increment();
    myCounter.increment();
    // myCounter.value = 100;  // Error! Field is private
    cout << "Value: " << myCounter.getValue() << endl;
    return 0;
}

Explanation: We hid the value field and provided only two methods: increment and getValue. No one can set the value directly — only through allowed operations.

Example 2: Setter with validation

class BankAccount {
private:
    double balance;

public:
    BankAccount() {
        balance = 0.0;
    }

    // Setter with validation
    void depositMoney(double amount) {
        if (amount > 0) {