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.
Desafio
FácilVamos 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 classeSecureMessageque armazena dados de mensagens privadas e concede acesso seletivo a entidades confiáveis. Sua classe deve ter:- Membros privados:
content(string) esecretKey(int) - Um construtor que recebe o conteúdo e a chave secreta
- Declare
MessageReadercomo 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
MessageReaderno mesmo arquivo de cabeçalho:- Um método
readContent(const SecureMessage& msg)que acessa diretamente e retorna ocontentprivado da mensagem - Um método
verifyKey(const SecureMessage& msg, int key)que verifica se a chave fornecida corresponde àsecretKeyda mensagem e retorna"Valid"ou"Invalid"
Por fim, defina a função amiga
decryptMessageapós as classes.- Membros privados:
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
SecureMessagecom o conteúdo e a chave secreta - Crie um objeto
MessageReader - Imprima
"Reader access: <content>"usando o métodoreadContent()do leitor - Imprima
"Key verification: <result>"usandoverifyKey()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
- Crie um
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;
}
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
1Fundamentos de OOP
Arquivos ExternosBuild e Compilação em C++Arquivos Header e SourceNamespaces e EscopoIntrodução a OOP em C++Classes vs ObjetosO Ponteiro 'this'Métodos (Funções Membro)Atributos (Membros de Dados)Básico de Ctors e DtorsRecapitulação - Calculadora Simples4Propriedades de Classe
Membros de Instância vs EstáticosGetters e SettersFunções de Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRecapitulação - Gerenciador de Conta Bancária7Herança
Herança BásicaNíveis de Acesso na HerançaOrdem de Chamada de Ctor e DtorSobrescrita de MétodosFunções Virtuais e VTableHerança MúltiplaHerança VirtualRecapitulação - Hierarquia de Funcionários2Gerenciamento de Memória
Memória Stack vs HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Smart Pointers em C++RAII em C++Recapitulação - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de Acesso em C++Especificadores de Acesso em DetalhesOcultação de InformaçãoStruct vs ClassClasses Aninhadas e InternasRecapitulação - Sistema de Registros de Alunos8Polimorfismo
Polimorfismo de Compilação vs Tempo de ExecuçãoSobrecarga de FunçõesFunções Virtuais RevisitadasFunções Virtuais PurasClasses AbstratasDesign de Interfaces em C++Dynamic Casting e RTTIRecapitulação - Calculadora de Formas3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentaçãoListas de Inicialização do ConstrutorConstrutores DelegadosMergulho Profundo em DestrutoresRegra dos Três / Cinco / ZeroRecapitulação - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de StreamSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçãoTemplates de ClasseEspecialização de TemplatesTemplates VariádicosFundamentos de SFINAE e Type TraitsRecapitulação - Container Genérico