Menu
Coddy logo textTech

Funciones y clases amigas

Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy — lección 32 de 104.

A veces, una función o clase fuera de su clase necesita acceder a sus miembros privados. En lugar de hacer que esos miembros sean públicos, C++ proporciona la palabra clave friend para otorgar acceso selectivo manteniendo el encapsulamiento.

Una función amiga se declara dentro de una clase, pero no es un miembro de esa clase. Puede acceder a los miembros privados y protegidos de la clase:

class Box {
    double width;
    
public:
    Box(double w) : width(w) {}
    
    // Declarar printWidth como friend
    friend void printWidth(const Box& b);
};

// Definición de la función friend - NO es una función miembro
void printWidth(const Box& b) {
    std::cout << b.width;    // Puede acceder al miembro privado
}

Observa que printWidth está definida fuera de la clase sin el operador de resolución de ámbito. Es una función regular que resulta tener privilegios de acceso especiales.

También puedes hacer que una clase entera sea amiga, otorgando a todas sus funciones miembro acceso a los miembros privados:

class Engine {
    int horsepower;
    
    friend class Mechanic;    // Mechanic puede acceder a miembros privados
    
public:
    Engine(int hp) : horsepower(hp) {}
};

class Mechanic {
public:
    void diagnose(const Engine& e) {
        std::cout << e.horsepower;    // Permitido - Mechanic es una clase amiga
    }
};

La amistad no es mutua: si Engine declara a Mechanic como amigo, Mechanic puede acceder a los miembros privados de Engine, pero no viceversa. Usa los amigos con moderación, ya que crean un acoplamiento fuerte entre clases. Son especialmente útiles para la sobrecarga de operadores y funciones auxiliares estrechamente relacionadas.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de mensajería segura donde una clase MessageReader necesita acceso especial para leer mensajes cifrados almacenados en una clase SecureMessage. Este es un escenario perfecto para usar funciones amigas (friend functions) y clases amigas (friend classes).

Crearás dos archivos para organizar tu código:

  • SecureMessage.h: Define una clase SecureMessage que almacena datos de mensajes privados y otorga acceso selectivo a entidades de confianza. Tu clase debe tener:
    • Miembros privados: content (string) y secretKey (int)
    • Un constructor que reciba el contenido y la clave secreta
    • Declarar MessageReader como una clase amiga para que pueda acceder a los miembros privados
    • Declarar una función amiga decryptMessage(const SecureMessage& msg, int key) que devuelva el contenido solo si la clave proporcionada coincide con la clave secreta, de lo contrario devuelve "Access Denied"

    Luego define la clase MessageReader en el mismo archivo de cabecera:

    • Un método readContent(const SecureMessage& msg) que acceda directamente y devuelva el content privado del mensaje
    • Un método verifyKey(const SecureMessage& msg, int key) que verifique si la clave proporcionada coincide con la secretKey del mensaje y devuelva "Valid" o "Invalid"

    Finalmente, define la función amiga decryptMessage después de las clases.

  • main.cpp: Demuestra tanto las funciones amigas como las clases amigas en acción. Lee el contenido de un mensaje, una clave secreta y una clave de prueba de la entrada (cada una en una línea separada), luego:
    • Crea un SecureMessage con el contenido y la clave secreta
    • Crea un objeto MessageReader
    • Imprime "Reader access: <content>" usando el método readContent() del lector
    • Imprime "Key verification: <result>" usando verifyKey() con la clave de prueba
    • Imprime "Decrypt with test key: <result>" usando la función amiga con la clave de prueba
    • Imprime "Decrypt with correct key: <result>" usando la función amiga con la clave secreta original

Recuerda que las funciones amigas se definen fuera de la clase sin el operador de resolución de ámbito; son funciones regulares con privilegios de acceso especiales. La clase MessageReader, al ser amiga, puede acceder directamente a los miembros privados de SecureMessage en todos sus métodos.

Convierte las entradas de las claves de cadenas a enteros usando std::stoi(). Incluye tu archivo de cabecera en main.cpp usando #include "SecureMessage.h".

Hoja de referencia

La palabra clave friend otorga acceso selectivo a miembros privados mientras mantiene el encapsulamiento.

Función Amiga (Friend Function): Una función declarada dentro de una clase que puede acceder a sus miembros privados y protegidos, pero no es un miembro de la clase:

class Box {
    double width;
    
public:
    Box(double w) : width(w) {}
    
    // Declarar función amiga
    friend void printWidth(const Box& b);
};

// Definir fuera de la clase sin el operador de resolución de ámbito
void printWidth(const Box& b) {
    std::cout << b.width;    // Puede acceder al miembro privado
}

Clase Amiga (Friend Class): Una clase entera puede ser declarada como amiga, otorgando a todas sus funciones miembro acceso a los miembros privados:

class Engine {
    int horsepower;
    
    friend class Mechanic;    // Todos los métodos de Mechanic pueden acceder a los miembros privados
    
public:
    Engine(int hp) : horsepower(hp) {}
};

class Mechanic {
public:
    void diagnose(const Engine& e) {
        std::cout << e.horsepower;    // Permitido
    }
};

Puntos Clave:

  • La amistad no es mutua: si A declara a B como amigo, B puede acceder a los miembros privados de A, pero no al revés
  • Las funciones amigas se definen fuera de la clase sin el operador de resolución de ámbito
  • Use las funciones amigas con moderación, ya que crean un acoplamiento fuerte entre las clases
  • Son más útiles para la sobrecarga de operadores y funciones auxiliares estrechamente relacionadas

Pruébalo tú mismo

#include <iostream>
#include <string>
#include "SecureMessage.h"
using namespace std;

int main() {
    // Leer la entrada
    string messageContent;
    string secretKeyStr;
    string testKeyStr;
    
    getline(cin, messageContent);
    getline(cin, secretKeyStr);
    getline(cin, testKeyStr);
    
    int secretKey = stoi(secretKeyStr);
    int testKey = stoi(testKeyStr);
    
    // TODO: Crear un SecureMessage con el contenido y la secret key
    
    // TODO: Crear un objeto MessageReader
    
    // TODO: Imprimir "Reader access: <content>" usando readContent()
    
    // TODO: Imprimir "Key verification: <result>" usando verifyKey() con test key
    
    // TODO: Imprimir "Decrypt with test key: <result>" usando decryptMessage con test key
    
    // TODO: Imprimir "Decrypt with correct key: <result>" usando decryptMessage con secret key
    
    return 0;
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos