Partilhar via


O que é uma interface COM?

Se você conhece C# ou Java, as interfaces devem ser um conceito familiar. Uma interface define um conjunto de métodos que um objeto pode suportar, sem ditar nada sobre a implementação. A interface marca um limite claro entre o código que chama um método e o código que implementa o método. Em termos de ciência da computação, o chamador é dissociado da implementação.

ilustração mostrando o limite da interface entre um objeto e um aplicativo

Em C++, o equivalente mais próximo de uma interface é uma classe virtual pura, ou seja, uma classe que contém apenas métodos virtuais puros e nenhum outro membro. Aqui está um exemplo hipotético de uma interface:

// The following is not actual COM.

// Pseudo-C++:

interface IDrawable
{
    void Draw();
};

A ideia deste exemplo é que um conjunto de objetos numa biblioteca gráfica seja desenhável. A interface IDrawable define as operações que qualquer objeto desenhável deve suportar. (Por convenção, os nomes das interfaces começam com "I".) Neste exemplo, a interface IDrawable define uma única operação: Draw.

Todas as interfaces são abstratas, de modo que um programa não poderia criar uma instância de um objeto IDrawable como tal. Por exemplo, o código a seguir não seria compilado.

IDrawable draw;
draw.Draw();

Em vez disso, a biblioteca de gráficos fornece objetos que implementam a interface IDrawable. Por exemplo, a biblioteca pode fornecer um objeto de forma para desenhar formas e um objeto de bitmap para desenhar imagens. Em C++, isso é feito herdando de uma classe base abstrata comum:

class Shape : public IDrawable
{
public:
    virtual void Draw();    // Override Draw and provide implementation.
};

class Bitmap : public IDrawable
{
public:
    virtual void Draw();    // Override Draw and provide implementation.
};

As classes Shape e Bitmap definem dois tipos distintos de objeto desenhável. Cada classe herda de IDrawable e fornece sua própria implementação do método Draw. Naturalmente, as duas implementações podem diferir consideravelmente. Por exemplo, o método Shape::Draw pode rasterizar um conjunto de linhas, enquanto o Bitmap::Draw blita uma matriz de píxeis.

Um programa usando essa biblioteca de gráficos manipularia Shape e Bitmap objetos através de ponteiros IDrawable, em vez de usar Shape ou ponteiros Bitmap diretamente.

IDrawable *pDrawable = CreateTriangleShape();

if (pDrawable)
{
    pDrawable->Draw();
}

Aqui está um exemplo que faz um loop sobre uma matriz de ponteiros de IDrawable. A matriz pode conter uma variedade heterogênea de formas, bitmaps e outros objetos gráficos, desde que cada objeto na matriz herde IDrawable.

void DrawSomeShapes(IDrawable **drawableArray, size_t count)
{
    for (size_t i = 0; i < count; i++)
    {
        drawableArray[i]->Draw();
    }
}

Um ponto-chave sobre COM é que o código de chamada nunca vê o tipo da classe derivada. Em outras palavras, você nunca declararia uma variável do tipo Shape ou Bitmap em seu código. Todas as operações em formas e bitmaps são executadas usando ponteiros IDrawable. Desta forma, a COM mantém uma separação rigorosa entre interface e implementação. Os detalhes de implementação das classes Shape e Bitmap podem ser alterados, por exemplo, para corrigir bugs ou adicionar novos recursos, sem alterações no código de chamada.

Em uma implementação C++, as interfaces são declaradas usando uma classe ou estrutura.

Observação

Os exemplos de código neste tópico destinam-se a transmitir conceitos gerais, não a prática do mundo real. Definir novas interfaces COM está além do escopo desta série, mas você não definiria uma interface diretamente em um arquivo de cabeçalho. Em vez disso, uma interface COM é definida usando uma linguagem chamada Interface Definition Language (IDL). O arquivo IDL é processado por um compilador IDL, que gera um arquivo de cabeçalho C++.

class IDrawable
{
public:
    virtual void Draw() = 0;
};

Quando você trabalha com COM, é importante lembrar que interfaces não são objetos. Eles são coleções de métodos que os objetos devem implementar. Vários objetos podem implementar a mesma interface, como mostrado com o Shape e Bitmap exemplos. Além disso, um objeto pode implementar várias interfaces. Por exemplo, a biblioteca de gráficos pode definir uma interface chamada ISerializable que suporte salvar e carregar objetos gráficos. Agora, considere as seguintes declarações de classe:

// An interface for serialization.
class ISerializable
{
public:
    virtual void Load(PCWSTR filename) = 0;    // Load from file.
    virtual void Save(PCWSTR filename) = 0;    // Save to file.
};

// Declarations of drawable object types.

class Shape : public IDrawable
{
    ...
};

class Bitmap : public IDrawable, public ISerializable
{
    ...
};

Neste exemplo, a classe Bitmap implementa ISerializable. O programa pode usar esse método para salvar ou carregar o bitmap. No entanto, a classe Shape não implementa ISerializable, portanto, não expõe essa funcionalidade. O diagrama a seguir mostra as relações de herança neste exemplo.

ilustração mostrando herança de interface, com as classes forma e bitmap apontando para IDrawable, mas apenas bitmap apontando para ISerializable

Esta seção examinou a base conceitual das interfaces, mas até agora não vimos o código COM real. Começaremos com a primeira coisa que qualquer aplicativo COM deve fazer: inicializar a biblioteca COM.

Próximo

Inicializando a biblioteca COM