Menu
Coddy logo textTech

Design de interfaces em C++

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

Uma interface em C++ é uma classe abstrata em que toda função-membro—exceto o destrutor (virtual)—é puramente virtual. Ao contrário das classes abstratas, que podem conter alguma implementação, as interfaces definem apenas quais operações devem existir — elas especificam um contrato sem qualquer comportamento.

class Drawable {
public:
    virtual void draw() = 0;
    virtual void resize(double factor) = 0;
    virtual ~Drawable() = default;
};

Esta interface Drawable garante que qualquer classe que a implemente terá os métodos draw() e resize(), mas não diz nada sobre como eles funcionam. Essa separação é poderosa — o código pode depender da interface sem saber nada sobre os tipos concretos.

class Circle : public Drawable {
    double radius;
public:
    Circle(double r) : radius(r) {}
    void draw() override { std::cout << "Drawing circle" << std::endl; }
    void resize(double factor) override { radius *= factor; }
};

class Button : public Drawable {
    std::string label;
public:
    Button(std::string l) : label(l) {}
    void draw() override { std::cout << "Drawing button: " << label << std::endl; }
    void resize(double factor) override { /* redimensionar botão */ }
};

Uma classe pode implementar várias interfaces, permitindo designs flexíveis nos quais os objetos podem desempenhar diferentes funções:

class Clickable {
public:
    virtual void onClick() = 0;
    virtual ~Clickable() = default;
};

class IconButton : public Drawable, public Clickable {
public:
    void draw() override { std::cout << "Drawing icon" << std::endl; }
    void resize(double factor) override { }
    void onClick() override { std::cout << "Clicked!" << std::endl; }
};

As interfaces promovem um baixo acoplamento — seu código depende de abstrações em vez de implementações concretas, o que facilita sua extensão e seus testes.

challenge icon

Desafio

Fácil

Vamos criar um sistema de gerenciamento de dispositivos que demonstra como as interfaces definem contratos para diferentes tipos de dispositivos. Você criará duas interfaces separadas que os dispositivos podem implementar e, em seguida, construirá classes concretas de dispositivos que atendem a um ou a ambos os contratos.

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

  • Interfaces.h: defina duas classes abstratas puras (interfaces) que representam diferentes capacidades dos dispositivos:

    Powerable: qualquer dispositivo que possa ser ligado e desligado:

    • Um método virtual puro powerOn()
    • Um método virtual puro powerOff()
    • Um método virtual puro getPowerStatus() que retorna uma std::string
    • Um destrutor virtual

    Connectable: qualquer dispositivo que possa se conectar a uma rede:

    • Um método virtual puro connect(const std::string& network)
    • Um método virtual puro disconnect()
    • Um método virtual puro getConnectionInfo() que retorna uma std::string
    • Um destrutor virtual
  • Devices.h: implemente classes concretas de dispositivos que usam essas interfaces:

    Lamp: implementa apenas Powerable:

    • Um membro privado bool isOn (começa como false)
    • Um membro privado std::string name
    • Um construtor que recebe o nome da lâmpada
    • powerOn() define isOn como true e imprime: <name>: Light turned on
    • powerOff() define isOn como false e imprime: <name>: Light turned off
    • getPowerStatus() retorna "ON" ou "OFF" com base no estado

    SmartTV: implementa Powerable e Connectable:

    • Membros privados: bool isOn (começa como false), std::string brand, std::string currentNetwork (começa vazio)
    • Um construtor que recebe a marca da TV
    • powerOn() define isOn como true e imprime: <brand> TV: Powered on
    • powerOff() define isOn como false, limpa a rede e imprime: <brand> TV: Powered off
    • getPowerStatus() retorna "ON" ou "OFF"
    • connect() armazena o nome da rede e imprime: <brand> TV: Connected to <network>
    • disconnect() limpa a rede e imprime: <brand> TV: Disconnected
    • getConnectionInfo() retorna "Connected to <network>" se estiver conectado ou "Not connected" se estiver vazia
  • main.cpp: leia três entradas (cada uma em uma linha separada):
    1. Nome da lâmpada
    2. Marca da TV
    3. Nome da rede

    Crie uma Lamp e uma SmartTV. Demonstre como a mesma interface pode ser usada com diferentes dispositivos:

    Primeiro, trabalhe com os dois dispositivos por meio da interface Powerable. Armazene ponteiros para ambos em um array de Powerable*, depois percorra o array e chame powerOn() em cada dispositivo, seguido da impressão do status no formato: Status: <powerStatus>

    Imprima uma linha em branco e, em seguida, trabalhe com a SmartTV por meio da interface Connectable. Crie um ponteiro Connectable* para sua SmartTV, chame connect() com o nome da rede e imprima: Connection: <connectionInfo>

    Imprima outra linha em branco e, em seguida, desligue os dois dispositivos por meio do array Powerable e mostre o status final deles.

Por exemplo, com as entradas Desk Lamp, Samsung e HomeWiFi:

Desk Lamp: Light turned on
Status: ON
Samsung TV: Powered on
Status: ON

Samsung TV: Connected to HomeWiFi
Connection: Connected to HomeWiFi

Desk Lamp: Light turned off
Status: OFF
Samsung TV: Powered off
Status: OFF

Observe como a SmartTV pode ser tratada como Powerable ou Connectable, dependendo de qual ponteiro de interface você usa. Essa flexibilidade é o poder de implementar múltiplas interfaces. Seu código pode trabalhar com qualquer dispositivo que cumpra o contrato necessário, sem conhecer o tipo concreto.

Experimente você mesmo

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

using namespace std;

int main() {
    // Ler entradas
    string lampName;
    string tvBrand;
    string networkName;
    
    getline(cin, lampName);
    getline(cin, tvBrand);
    getline(cin, networkName);
    
    // TODO: Criar um objeto Lamp e um SmartTV
    
    // TODO: Criar um array de ponteiros Powerable* contendo ambos os dispositivos
    
    // TODO: Percorrer o array e chamar powerOn() em cada dispositivo
    // Após cada powerOn(), imprimir: Status: <powerStatus>
    
    // TODO: Imprimir uma linha em branco
    
    // TODO: Criar um ponteiro Connectable* para o SmartTV
    // Chamar connect() com o nome da rede
    // Print: Connection: <connectionInfo>
    
    // TODO: Imprimir uma linha em branco
    
    // TODO: Percorrer o array Powerable e chamar powerOff() em cada dispositivo
    // Após cada powerOff(), imprimir: Status: <powerStatus>
    
    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