Condividi tramite


Che cos'è un'interfaccia COM?

Se si conosce C# o Java, le interfacce devono essere un concetto familiare. Un'interfaccia definisce un set di metodi che un oggetto può supportare, senza dettare nulla sull'implementazione. L'interfaccia contrassegna un limite chiaro tra il codice che chiama un metodo e il codice che implementa il metodo . In termini informatici, il chiamante è disaccoppiato dalla implementazione.

illustrazione che mostra il limite di interfaccia tra un oggetto e un'applicazione

In C++, l'equivalente più vicino a un'interfaccia è una classe virtuale pura, ovvero una classe che contiene solo metodi virtuali puri e nessun altro membro. Ecco un esempio ipotetico di un'interfaccia:

// The following is not actual COM.

// Pseudo-C++:

interface IDrawable
{
    void Draw();
};

L'idea di questo esempio è che un set di oggetti in alcune librerie grafiche è disegnabile. L'interfaccia IDrawable definisce le operazioni che devono essere supportate da qualsiasi oggetto drawable. Per convenzione, i nomi di interfaccia iniziano con "I". In questo esempio, l'interfaccia IDrawable definisce una singola operazione: Draw.

Tutte le interfacce sono astratta, quindi un programma non è in grado di creare un'istanza di un oggetto IDrawable come tale. Ad esempio, il codice seguente non viene compilato.

IDrawable draw;
draw.Draw();

La libreria grafica fornisce invece oggetti che implementare'interfaccia di IDrawable. Ad esempio, la libreria potrebbe fornire un oggetto forma per disegnare forme e un oggetto bitmap per disegnare immagini. In C++, questa operazione viene eseguita ereditando da una classe base astratta comune:

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.
};

Le classi Shape e Bitmap definiscono due tipi distinti di oggetto drawable. Ogni classe eredita da IDrawable e fornisce la propria implementazione del metodo Draw. Naturalmente, le due implementazioni potrebbero differire notevolmente. Ad esempio, il metodo Shape::Draw potrebbe rasterizzare un set di righe, mentre Bitmap::Draw potrebbe blitare una matrice di pixel.

Un programma che usa questa libreria grafica modifica gli oggetti Shape e Bitmap tramite puntatori IDrawable anziché usare direttamente i puntatori Shape o Bitmap.

IDrawable *pDrawable = CreateTriangleShape();

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

Di seguito è riportato un esempio che esegue un ciclo su una matrice di puntatori IDrawable. La matrice può contenere un assortimento eterogeneo di forme, bitmap e altri oggetti grafici, purché ogni oggetto nella matrice erediti IDrawable.

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

Un punto chiave su COM è che il codice chiamante non vede mai il tipo della classe derivata. In altre parole, non si dichiara mai una variabile di tipo Shape o Bitmap nel codice. Tutte le operazioni su forme e bitmap vengono eseguite usando IDrawable puntatori. In questo modo, COM mantiene una rigorosa separazione tra l'interfaccia e l'implementazione. I dettagli di implementazione delle classi Shape e Bitmap possono cambiare, ad esempio per correggere i bug o aggiungere nuove funzionalità, senza modifiche al codice chiamante.

In un'implementazione C++ le interfacce vengono dichiarate usando una classe o una struttura.

Nota

Gli esempi di codice in questo argomento sono destinati a trasmettere concetti generali, non pratiche reali. La definizione di nuove interfacce COM non rientra nell'ambito di questa serie, ma non si definirà un'interfaccia direttamente in un file di intestazione. Al contrario, un'interfaccia COM viene definita usando un linguaggio denominato IDL (Interface Definition Language). Il file IDL viene elaborato da un compilatore IDL, che genera un file di intestazione C++.

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

Quando si lavora con COM, è importante ricordare che le interfacce non sono oggetti. Sono raccolte di metodi che gli oggetti devono implementare. Diversi oggetti possono implementare la stessa interfaccia, come illustrato con gli esempi di Shape e Bitmap. Inoltre, un oggetto può implementare diverse interfacce. Ad esempio, la libreria grafica potrebbe definire un'interfaccia denominata ISerializable che supporta il salvataggio e il caricamento di oggetti grafici. Si considerino ora le dichiarazioni di classe seguenti:

// 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
{
    ...
};

In questo esempio la classe Bitmap implementa ISerializable. Il programma potrebbe usare questo metodo per salvare o caricare la bitmap. Tuttavia, la classe Shape non implementa ISerializable, quindi non espone tale funzionalità. Il diagramma seguente illustra le relazioni di ereditarietà in questo esempio.

illustrazione che mostra l'ereditarietà dell'interfaccia, con le classi shape e bitmap che puntano a idrawable, ma solo bitmap che puntano a iserializable

Questa sezione ha esaminato la base concettuale delle interfacce, ma finora non è stato rilevato codice COM effettivo. Si inizierà con la prima cosa che deve fare qualsiasi applicazione COM: Inizializzare la libreria COM.

Prossimo

Inizializzazione della libreria COM