Ponteiros para Funções em C++

Para Estudantes de Engenharia

Tópicos

  • O que são ponteiros para funções
  • Sintaxe e declaração
  • Callbacks
  • Padrões de design básicos
  • Exemplos práticos
  • Casos de uso comuns

O que são Ponteiros para Funções?

  • Variáveis que armazenam o endereço de funções na memória
  • Permitem chamar funções indiretamente
  • Possibilitam passar comportamento como parâmetro
  • Base para vários padrões de programação

Sintaxe Básica

// Declaração de um ponteiro para função
// que recebe dois ints e retorna um int
int (*funcPtr)(int, int);

// Função exemplo
int soma(int a, int b) {
    return a + b;
}

// Atribuição
funcPtr = &soma;  // ou simplesmente funcPtr = soma;

// Chamada através do ponteiro
int resultado = (*funcPtr)(5, 3);  // ou simplesmente funcPtr(5, 3);

Simplificando a Sintaxe

// Usando typedef para criar um alias
typedef int (*OperacaoMatematica)(int, int);

// Agora podemos declarar ponteiros para função assim:
OperacaoMatematica operacao;
operacao = soma;

// Mais legível e fácil de entender
int resultado = operacao(5, 3);

Exemplo: Biblioteca de Operações Matemáticas

// Funções básicas
int soma(int a, int b) { return a + b; }
int subtracao(int a, int b) { return a - b; }
int multiplicacao(int a, int b) { return a * b; }
int divisao(int a, int b) { return b != 0 ? a / b : 0; }

// Array de ponteiros para funções
typedef int (*Operacao)(int, int);
Operacao operacoes[] = {soma, subtracao, multiplicacao, divisao};

// Função que executa a operação escolhida
int calculadora(int a, int b, int op) {
    if (op >= 0 && op < 4) {
        return operacoes[op](a, b);
    }
    return 0;
}

Callbacks: Conceito Fundamental

  • Callback: função passada como argumento para outra função
  • Permite personalizar comportamento
  • Muito usado em processamento de dados
  • Base para programação orientada a eventos

Exemplo: Processamento de Arrays

// Função que processa cada elemento de um array
void processarArray(int arr[], int tamanho, int (*processador)(int)) {
    for(int i = 0; i < tamanho; i++) {
        arr[i] = processador(arr[i]);
    }
}

// Funções de processamento
int dobrar(int x) { return x * 2; }
int quadrado(int x) { return x * x; }
int absoluto(int x) { return x < 0 ? -x : x; }

// Uso
int numeros[] = {1, -2, 3, -4, 5};
processarArray(numeros, 5, dobrar);    // Dobra todos os números
processarArray(numeros, 5, quadrado);  // Eleva ao quadrado
processarArray(numeros, 5, absoluto);  // Valor absoluto

Padrão de Design: Table-Driven Methods

// Estrutura para manter dados e comportamento juntos
struct Comando {
    const char* nome;
    void (*executar)(void);
};

// Funções de comando
void salvar(void) {
    printf("Salvando dados...\n");
}

void carregar(void) {
    printf("Carregando dados...\n");
}

// Tabela de comandos
Comando comandos[] = {
    {"salvar", salvar},
    {"carregar", carregar}
};

Padrão de Design: Chain of Responsibility

// Função que processa um valor
typedef int (*Processador)(int);

// Estrutura para criar uma cadeia de processadores
struct CadeiaProcessamento {
    Processador processadores[10];
    int quantidade;
};

// Inicializa a cadeia
void iniciarCadeia(CadeiaProcessamento* cadeia) {
    cadeia->quantidade = 0;
}

// Adiciona um processador à cadeia
void adicionarProcessador(CadeiaProcessamento* cadeia, Processador p) {
    if(cadeia->quantidade < 10) {
        cadeia->processadores[cadeia->quantidade++] = p;
    }
}

Exemplo: Sistema de Filtragem

// Funções de filtro
int filtroNegativo(int x) {
    return x < 0 ? 0 : x;
}

int filtroMaximo(int x) {
    return x > 100 ? 100 : x;
}

// Uso do sistema
CadeiaProcessamento filtros;
iniciarCadeia(&filtros);
adicionarProcessador(&filtros, filtroNegativo);
adicionarProcessador(&filtros, filtroMaximo);

// Processa um valor através de todos os filtros
int resultado = processarValor(&filtros, -50);  // Resultado: 0
resultado = processarValor(&filtros, 150);      // Resultado: 100

Casos de Uso Comuns

  1. Processamento de Dados
    • Filtros
    • Transformações
    • Validações
  2. Menus e Comandos
    • Sistemas de menu
    • Interpretadores de comando
    • Mapeamento ação-função

Boas Práticas

  1. Use typedef para simplificar a sintaxe
  2. Verifique ponteiros para função antes de chamá-los
  3. Mantenha a documentação clara sobre o comportamento esperado
  4. Use constantes para identificar operações
  5. Agrupe funções relacionadas em estruturas

Considerações Finais

  • Ponteiros para funções são fundamentais em C++
  • Permitem criar código mais flexível e reutilizável
  • São a base para vários padrões de design
  • Importantes para sistemas modulares
  • Essenciais para callbacks e processamento de eventos