Menu
Coddy logo textTech

Funções e Classes Friend

Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy — lição 32 de 104.

Às vezes, uma função ou classe fora da sua classe precisa de acesso aos seus membros privados. Em vez de tornar esses membros públicos, o C++ fornece a palavra-chave friend para conceder acesso seletivo, mantendo o encapsulamento.

Uma função amiga (friend function) é declarada dentro de uma classe, mas não é um membro dessa classe. Ela pode acessar os membros privados e protegidos da classe:

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

// Definição da função friend - NÃO é uma função membro
void printWidth(const Box& b) {
    std::cout << b.width;    // Pode acessar membro privado
}

Observe que printWidth é definida fora da classe sem o operador de resolução de escopo. É uma função comum que por acaso possui privilégios de acesso especiais.

Você também pode tornar uma classe inteira amiga, concedendo a todas as suas funções membros acesso a membros privados:

class Engine {
    int horsepower;
    
    friend class Mechanic;    // Mechanic pode acessar membros privados
    
public:
    Engine(int hp) : horsepower(hp) {}
};

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

A amizade não é mútua - se Engine declarar Mechanic como amiga, Mechanic pode acessar os membros privados de Engine, mas não o contrário. Use amizades com moderação, pois elas criam um acoplamento forte entre as classes. Elas são mais úteis para sobrecarga de operadores e funções auxiliares estreitamente relacionadas.

challenge icon

Desafio

Fácil

Vamos construir um sistema de mensagens seguro onde uma classe MessageReader precisa de acesso especial para ler mensagens criptografadas armazenadas em uma classe SecureMessage. Este é um cenário perfeito para usar funções amigas (friend functions) e classes amigas (friend classes).

Você criará dois arquivos para organizar seu código:

  • SecureMessage.h: Defina uma classe SecureMessage que armazena dados de mensagens privadas e concede acesso seletivo a entidades confiáveis. Sua classe deve ter:
    • Membros privados: content (string) e secretKey (int)
    • Um construtor que recebe o conteúdo e a chave secreta
    • Declare MessageReader como uma classe amiga para que ela possa acessar membros privados
    • Declare uma função amiga decryptMessage(const SecureMessage& msg, int key) que retorna o conteúdo apenas se a chave fornecida corresponder à chave secreta, caso contrário, retorna "Access Denied"

    Em seguida, defina a classe MessageReader no mesmo arquivo de cabeçalho:

    • Um método readContent(const SecureMessage& msg) que acessa diretamente e retorna o content privado da mensagem
    • Um método verifyKey(const SecureMessage& msg, int key) que verifica se a chave fornecida corresponde à secretKey da mensagem e retorna "Valid" ou "Invalid"

    Por fim, defina a função amiga decryptMessage após as classes.

  • main.cpp: Demonstre tanto as funções amigas quanto as classes amigas em ação. Leia o conteúdo de uma mensagem, uma chave secreta e uma chave de teste da entrada (cada uma em uma linha separada), então:
    • Crie um SecureMessage com o conteúdo e a chave secreta
    • Crie um objeto MessageReader
    • Imprima "Reader access: <content>" usando o método readContent() do leitor
    • Imprima "Key verification: <result>" usando verifyKey() com a chave de teste
    • Imprima "Decrypt with test key: <result>" usando a função amiga com a chave de teste
    • Imprima "Decrypt with correct key: <result>" usando a função amiga com a chave secreta original

Lembre-se de que as funções amigas são definidas fora da classe sem o operador de resolução de escopo — elas são funções normais com privilégios de acesso especiais. A classe MessageReader, sendo uma amiga, pode acessar diretamente os membros privados de SecureMessage em todos os seus métodos.

Converta as entradas de chave de strings para inteiros usando std::stoi(). Inclua seu arquivo de cabeçalho no main.cpp usando #include "SecureMessage.h".

Folha de consulta

A palavra-chave friend concede acesso seletivo a membros privados, mantendo o encapsulamento.

Função Amiga (Friend Function): Uma função declarada dentro de uma classe que pode acessar seus membros privados e protegidos, mas não é um membro da classe:

class Box {
    double width;
    
public:
    Box(double w) : width(w) {}
    
    // Declara a função amiga
    friend void printWidth(const Box& b);
};

// Define fora da classe sem o operador de resolução de escopo
void printWidth(const Box& b) {
    std::cout << b.width;    // Pode acessar membro privado
}

Classe Amiga (Friend Class): Uma classe inteira pode ser declarada como amiga, concedendo a todas as suas funções membros o acesso a membros privados:

class Engine {
    int horsepower;
    
    friend class Mechanic;    // Todos os métodos de Mechanic podem acessar membros privados
    
public:
    Engine(int hp) : horsepower(hp) {}
};

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

Pontos Chave:

  • A amizade não é mútua - se A declara B como amigo, B pode acessar os membros privados de A, mas não vice-versa
  • Funções amigas são definidas fora da classe sem o operador de resolução de escopo
  • Use friends com moderação, pois eles criam um acoplamento forte entre as classes
  • Mais útil para sobrecarga de operadores e funções auxiliares intimamente relacionadas

Experimente você mesmo

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

int main() {
    // Ler 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: Criar um SecureMessage com o conteúdo e a chave secreta (secret key)
    
    // TODO: Criar um objeto MessageReader
    
    // TODO: Imprimir "Reader access: <content>" usando readContent()
    
    // TODO: Imprimir "Key verification: <result>" usando verifyKey() com a chave de teste (test key)
    
    // TODO: Imprimir "Decrypt with test key: <result>" usando decryptMessage com a chave de teste (test key)
    
    // TODO: Imprimir "Decrypt with correct key: <result>" usando decryptMessage com a chave secreta (secret key)
    
    return 0;
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos