Menu
Coddy logo textTech

Funções virtuais puras

Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy. Lição 59 de 104.

Uma função virtual pura é uma função virtual que não possui implementação na classe base. Ela é declarada atribuindo = 0 à declaração da função. Isso informa ao compilador que as classes derivadas devem fornecer sua própria implementação.

class Shape {
public:
    virtual double area() = 0;  // Função virtual pura
    virtual ~Shape() = default;
};

Ao contrário das funções virtuais comuns, que fornecem um comportamento padrão, as funções virtuais puras definem um contrato: qualquer classe derivada concreta deve implementar esta função para ser instanciável. A classe base simplesmente declara o que deve ser feito, não como.

class Circle : public Shape {
    double radius;
public:
    Circle(double r) : radius(r) {}
    
    double area() override {
        return 3.14159 * radius * radius;
    }
};

class Rectangle : public Shape {
    double width, height;
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    
    double area() override {
        return width * height;
    }
};

Tanto Circle quanto Rectangle devem implementar area() porque ela é puramente virtual em Shape. Se uma classe derivada não implementar todas as funções puramente virtuais, ela também se tornará abstrata e não poderá ser instanciada.

Funções virtuais puras são essenciais quando a classe-base não pode fornecer uma implementação padrão significativa. Toda forma tem uma área, mas não há uma maneira sensata de calcular a “área de uma forma genérica” sem conhecer o tipo específico da forma.

challenge icon

Desafio

Fácil

Vamos criar um sistema de processamento de pagamentos que demonstra como funções virtuais puras impõem um contrato entre diferentes métodos de pagamento. Você criará uma classe base abstrata que define o que todo processador de pagamentos deve fazer e, em seguida, implementará tipos concretos de pagamento que cumprem esse contrato.

Você organizará seu código em três arquivos:

  • PaymentProcessor.h: Defina uma classe abstrata PaymentProcessor que serve como modelo para todos os métodos de pagamento. Essa classe deve ter:
    • Um membro std::string accountId protegido
    • Um construtor que inicializa o ID da conta
    • Um método virtual puro processPayment(double amount): cada tipo de pagamento deve implementá-lo de forma diferente
    • Um método virtual puro getProcessorName() que retorna uma std::string
    • Um destrutor virtual
  • PaymentMethods.h: Implemente dois processadores de pagamento concretos que herdam de PaymentProcessor:

    CreditCardProcessor:

    • Um membro privado double feePercentage (a taxa da transação)
    • Um construtor que recebe o ID da conta e o percentual da taxa
    • Implemente processPayment() para calcular a taxa (amount * feePercentage / 100) e, em seguida, imprimir:
      Credit Card [<accountId>]: Charged $<amount> (Fee: $<fee>)
    • Implemente getProcessorName() para retornar "CreditCard"

    BankTransferProcessor:

    • Um membro privado std::string bankName
    • Um construtor que recebe o ID da conta e o nome do banco
    • Implemente processPayment() para imprimir:
      Bank Transfer [<accountId>] via <bankName>: Transferred $<amount>
    • Implemente getProcessorName() para retornar "BankTransfer"
  • main.cpp: Leia quatro entradas (cada uma em uma linha separada):
    1. ID da conta do cartão de crédito
    2. Percentual da taxa do cartão de crédito (double)
    3. ID da conta bancária
    4. Nome do banco

    Crie ambos os processadores de pagamento e armazene-os em um array de ponteiros PaymentProcessor*. Processe um pagamento de 100.0 por meio de cada processador, exibindo o nome do processador antes de cada transação:

    Processing with <processorName>:
    <processPayment output>

    Imprima uma linha em branco entre os processadores. Libere os objetos alocados dinamicamente ao terminar.

Por exemplo, com as entradas CC-4521, 2.5, BA-7890 e National Bank:

Processing with CreditCard:
Credit Card [CC-4521]: Charged $100 (Fee: $2.5)

Processing with BankTransfer:
Bank Transfer [BA-7890] via National Bank: Transferred $100

Como PaymentProcessor possui funções virtuais puras, você não pode instanciá-la diretamente: somente as implementações concretas que cumprem o contrato podem ser criadas. Isso garante que cada método de pagamento forneça sua própria lógica específica de processamento.

Experimente você mesmo

#include <iostream>
#include <string>
#include "PaymentMethods.h"

using namespace std;

int main() {
    // Ler entradas
    string ccAccountId;
    double feePercentage;
    string bankAccountId;
    string bankName;
    
    getline(cin, ccAccountId);
    cin >> feePercentage;
    cin.ignore();
    getline(cin, bankAccountId);
    getline(cin, bankName);
    
    // TODO: Crie um array de ponteiros PaymentProcessor* com 2 elementos
    
    // TODO: Crie objetos CreditCardProcessor e BankTransferProcessor
    // e armazene-os no array
    
    // TODO: Percorra o array e para cada processador:
    // 1. Print "Processing with <processorName>:"
    // 2. Chame processPayment com o valor 100.0
    // 3. Imprima uma linha em branco entre os processadores (não após o último)
    
    // TODO: Limpe os objetos alocados dinamicamente
    
    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

Pratique por conta própria: Compilador de C++ online