Qu’est-ce qu’une interface COM ?

Si vous connaissez C# ou Java, les interfaces doivent être un concept familier. Une interface définit un ensemble de méthodes qu’un objet peut prendre en charge, sans rien dicter sur l’implémentation. L’interface marque une limite claire entre le code qui appelle une méthode et le code qui implémente la méthode. En termes informatiques, l’appelant est dissocié de l’implémentation.

illustration montrant la limite d’interface entre un objet et une application

En C++, l’équivalent le plus proche d’une interface est une classe virtuelle pure, c’est-à-dire une classe qui contient uniquement des méthodes virtuelles pures et aucun autre membre. Voici un exemple hypothétique d’interface :

// The following is not actual COM.

// Pseudo-C++:

interface IDrawable
{
    void Draw();
};

L’idée de cet exemple est qu’un ensemble d’objets dans une bibliothèque graphique est dessinable. L’interface IDrawable définit les opérations que tout objet dessinable doit prendre en charge. (Par convention, les noms d’interface commencent par « I ».) Dans cet exemple, l’interface IDrawable définit une seule opération : Draw.

Toutes les interfaces étant abstraites, un programme n’a pas pu créer une instance d’un IDrawable objet en tant que tel. Par exemple, le code suivant ne sera pas compilé.

IDrawable draw;
draw.Draw();

Au lieu de cela, la bibliothèque graphique fournit des objets qui implémentent l’interface IDrawable . Par exemple, la bibliothèque peut fournir un objet shape pour dessiner des formes et un objet bitmap pour dessiner des images. En C++, cette opération s’effectue en héritant d’une classe de base abstraite commune :

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

Les Shape classes et Bitmap définissent deux types distincts d’objet dessinable. Chaque classe hérite de IDrawable et fournit sa propre implémentation de la Draw méthode . Naturellement, les deux implémentations peuvent différer considérablement. Par exemple, la Shape::Draw méthode peut rastériser un ensemble de lignes, tandis qu’elle Bitmap::Draw blit un tableau de pixels.

Un programme utilisant cette bibliothèque graphique manipulerait Shape les objets et Bitmap par le biais IDrawable de pointeurs, plutôt que d’utiliser Shape des pointeurs ou Bitmap directement.

IDrawable *pDrawable = CreateTriangleShape();

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

Voici un exemple qui effectue une boucle sur un tableau de IDrawable pointeurs. Le tableau peut contenir un assortiment hétérogène de formes, bitmaps et autres objets graphiques, tant que chaque objet du tableau hérite IDrawablede .

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

Un point clé à propos de COM est que le code appelant ne voit jamais le type de la classe dérivée. En d’autres termes, vous ne déclareriez jamais une variable de type Shape ou Bitmap dans votre code. Toutes les opérations sur les formes et les bitmaps sont effectuées à l’aide IDrawable de pointeurs. De cette façon, COM maintient une séparation stricte entre l’interface et l’implémentation. Les détails d’implémentation des Shape classes et peuvent Bitmap changer, par exemple pour corriger des bogues ou ajouter de nouvelles fonctionnalités, sans aucune modification du code appelant.

Dans une implémentation C++, les interfaces sont déclarées à l’aide d’une classe ou d’une structure.

Notes

Les exemples de code de cette rubrique sont destinés à transmettre des concepts généraux, et non des pratiques réelles. La définition de nouvelles interfaces COM dépasse le cadre de cette série, mais vous ne définiriez pas d’interface directement dans un fichier d’en-tête. Au lieu de cela, une interface COM est définie à l’aide d’un langage appelé IDL (Interface Definition Language). Le fichier IDL est traité par un compilateur IDL, qui génère un fichier d’en-tête C++.

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

Lorsque vous utilisez COM, il est important de se rappeler que les interfaces ne sont pas des objets. Il s’agit de collections de méthodes que les objets doivent implémenter. Plusieurs objets peuvent implémenter la même interface, comme le montrent les Shape exemples et Bitmap . En outre, un objet peut implémenter plusieurs interfaces. Par exemple, la bibliothèque graphique peut définir une interface nommée ISerializable qui prend en charge l’enregistrement et le chargement d’objets graphiques. Considérez maintenant les déclarations de classe suivantes :

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

Dans cet exemple, la Bitmap classe implémente ISerializable. Le programme peut utiliser cette méthode pour enregistrer ou charger la bitmap. Toutefois, la classe n’implémente ShapeISerializablepas , elle n’expose donc pas cette fonctionnalité. Le diagramme suivant montre les relations d’héritage dans cet exemple.

illustration montrant l’héritage d’interface, avec les classes shape et bitmap pointant vers idrawable, mais uniquement bitmap pointant vers isérialisable

Cette section a examiné la base conceptuelle des interfaces, mais jusqu’à présent, nous n’avons pas vu de code COM réel. Nous allons commencer par la première chose que toute application COM doit faire : initialiser la bibliothèque COM.

Suivant

Initialisation de la bibliothèque COM