Cargando...

Encapsulación y modificadores de acceso en C++ (public, protected, private)

Aprende encapsulación y modificadores de acceso en C++ con public, protected y private para diseñar clases seguras.

Encapsulación es uno de los cuatro conceptos fundamentales de la Programación Orientada a Objetos (POO). Consiste en ocultar los datos (atributos) de una clase del mundo exterior y permitir el acceso a ellos solo a través de métodos definidos. Este enfoque protege la integridad de los datos y hace que la estructura interna de una clase sea independiente del uso externo.


1) ¿Qué es la encapsulación?

La encapsulación es el principio de “ocultamiento de datos”. Los detalles internos de una clase (atributos, métodos auxiliares) están ocultos al exterior. El usuario interactúa únicamente mediante la interfaz pública de la clase.

Ventajas de la encapsulación:


2) Modificadores de acceso

En C++, existen tres tipos de modificadores de acceso:

Modificador Nivel de acceso Uso
public Accesible desde cualquier parte Interfaz pública de la clase (API)
protected Accesible solo dentro de la clase y las clases derivadas Comportamientos comunes utilizados en la herencia
private Accesible solo dentro de la clase Campos de datos, funciones auxiliares

3) Ejemplo de encapsulación con la clase Book

A continuación, un ejemplo de una clase Book que demuestra el principio de encapsulación.


#include <iostream>
#include <string>
using namespace std;

class Book {
private:
    string title;
    string author;
    double price;
    int pageCount;

public:
    // Constructor
    Book(string t, string a, double p, int pc)
        : title(t), author(a), price(p), pageCount(pc) {}

    // Getters y Setters
    string GetTitle() const { return title; }
    string GetAuthor() const { return author; }

    double GetPrice() const { return price; }
    void SetPrice(double p) {
        if (p >= 0) price = p;
        else cout << "¡El precio no puede ser negativo!" << endl;
    }

    int GetPageCount() const { return pageCount; }

    void Print() const {
        cout << "Libro: " << title
             << " | Autor: " << author
             << " | Páginas: " << pageCount
             << " | Precio: " << price << " €" << endl;
    }
};

int main() {
    Book b("C++ Primer", "Lippman", 180.0, 950);

    b.Print();
    b.SetPrice(-50); // Inválido
    b.SetPrice(210);
    b.Print();
}

Los campos private no pueden modificarse directamente. Las modificaciones deben hacerse a través de métodos controlados como SetPrice().


4) Campos protegidos y herencia

Las clases derivadas pueden acceder directamente a los campos protected. Esto permite que la subclase amplíe o reutilice los datos de la clase base.


class EBook : public Book {
protected:
    string format; // Ejemplo: PDF, EPUB

public:
    EBook(string t, string a, double p, int pc, string f)
        : Book(t, a, p, pc), format(f) {}

    void PrintWithFormat() const {
        cout << GetTitle() << " (" << format << ")" << endl;
    }
};

Aquí, la clase derivada añade una nueva propiedad (format) sin violar la encapsulación.


5) La palabra clave friend

Normalmente, los miembros private solo son accesibles dentro de la clase. Sin embargo, a veces otra clase o función necesita acceder a esos datos privados. En tales casos, se puede usar la declaración friend.


class Book {
private:
    string title;
    double price;
public:
    Book(string t, double p) : title(t), price(p) {}

    // Declaración de función amiga
    friend void ApplyDiscount(Book& b, double rate);
};

void ApplyDiscount(Book& b, double rate) {
    b.price *= (1 - rate); // acceso al miembro privado
}

int main() {
    Book b("Design Patterns", 300);
    ApplyDiscount(b, 0.1);
}

El uso de friend debe hacerse con precaución, ya que rompe la encapsulación. Solo debe usarse cuando sea necesario (por ejemplo: sobrecarga de operadores o herramientas de depuración).


6) Principios de diseño de getters y setters


class Book {
private:
    string title;
    double price;
public:
    Book(string t, double p) : title(t), price(p) {}

    string GetTitle() const { return title; } // solo lectura
    void ApplyDiscount(double rate) { price *= (1 - rate); } // comportamiento en lugar de setter
};

7) Seguridad de datos con la palabra clave const

Los métodos const no modifican el estado de la clase. Esto apoya la encapsulación y evita modificaciones inesperadas.


class SafeBook {
private:
    string title;
public:
    SafeBook(string t) : title(t) {}

    string GetTitle() const { return title; } // método const
    void SetTitle(string t) { title = t; }
};

Un método Get escrito sin const viola este principio y puede causar errores inesperados.


8) Patrón de objeto inmutable (Immutable)

De acuerdo con el principio de encapsulación, algunos objetos se diseñan para ser “inmutables”. Todos sus miembros se declaran const y no tienen métodos setter.


class ImmutableBook {
private:
    const string title;
    const string author;
    const int pages;
public:
    ImmutableBook(string t, string a, int p)
        : title(t), author(a), pages(p) {}

    string GetTitle() const { return title; }
    string GetAuthor() const { return author; }
    int GetPages() const { return pages; }
};

Este enfoque garantiza la integridad de los datos, especialmente en entornos multihilo.


9) Encapsulación y gestión del estado del objeto

La encapsulación no solo controla el acceso, sino que también garantiza que el objeto permanezca en un estado válido. El estado interno de la clase siempre debe tener valores coherentes.


class ValidatedBook {
private:
    double price;
public:
    void SetPrice(double p) {
        if (p < 0) throw invalid_argument("El precio no puede ser negativo.");
        price = p;
    }
};

Estos mecanismos de validación garantizan que la clase mantenga un “estado válido” y evitan que el código externo proporcione datos incorrectos.


10) TL;DR

  • La encapsulación consiste en ocultar los datos y acceder a ellos a través de un comportamiento controlado.
  • private: accesible solo dentro de la clase.
  • protected: accesible dentro de la clase y sus subclases.
  • public: accesible desde cualquier lugar (interfaz de la clase).
  • friend permite acceso externo a datos privados (úsese con precaución).
  • La validación y el uso de const en getters/setters son fundamentales.
  • Los objetos inmutables aumentan la seguridad de los datos.
  • La encapsulación es un principio esencial para diseños mantenibles y sin errores.
  • Todos los ejemplos pueden ejecutarse en Visual Studio 2022 o GCC 11+.

Artículos relacionados