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 externa a tu clase necesita acceder a sus miembros privados. En lugar de hacer públicos esos miembros, C++ proporciona la palabra clave friend para conceder acceso selectivo y mantener la encapsulación.

Una función amiga se declara dentro de una clase, pero no es 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) {}
    
    // Declara printWidth como friend
    friend void printWidth(const Box& b);
};

// Definición de 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á definido fuera de la clase sin el operador de resolución de ámbito. Es una función regular que casualmente tiene privilegios de acceso especiales.

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

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

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

La amistad no es mutua: si Engine declara a Mechanic como amigo, Mechanic puede acceder a los miembros privados de Engine, pero no al revés. Usa las amistades con moderación, ya que crean un acoplamiento estrecho entre las clases. Son más útiles para la sobrecarga de operadores y las funciones auxiliares estrechamente relacionadas.

challenge icon

Desafío

Fácil

Construyamos un sistema de mensajería seguro en el que una clase MessageReader necesite acceso especial para leer mensajes cifrados almacenados en una clase SecureMessage. Este es un escenario perfecto para usar funciones amigas y clases amigas.

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

  • SecureMessage.h: Define una clase SecureMessage que almacene datos privados del mensaje y conceda acceso selectivo a entidades de confianza. Tu clase debe tener:
    • Miembros privados: content (cadena) y secretKey (entero)
    • Un constructor que reciba el contenido y la clave secreta
    • Declarar MessageReader como 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"

    Después define la clase MessageReader en el mismo archivo de cabecera:

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

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

  • main.cpp: Demuestra en acción tanto las funciones amigas como las clases amigas. Lee el contenido de un mensaje, una clave secreta y una clave de prueba de la entrada (cada uno en una línea separada) y, después:
    • 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 normales 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 el archivo de cabecera en main.cpp usando #include "SecureMessage.h".

Pruébalo tú mismo

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

int main() {
    // Leer 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: Crea un SecureMessage con el contenido y la clave secreta
    
    // TODO: Crea un objeto MessageReader
    
    // TODO: Print "Reader access: <content>" using readContent()
    
    // TODO: Print "Key verification: <result>" using verifyKey() with test key
    
    // TODO: Print "Decrypt with test key: <result>" using decryptMessage with test key
    
    // TODO: Print "Decrypt with correct key: <result>" using decryptMessage with 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

Practica por tu cuenta: Compilador de C++ online