Was ist eine COM-Schnittstelle?
Wenn Sie C# oder Java kennen, sollten Schnittstellen ein vertrautes Konzept sein. Eine Schnittstelle definiert eine Reihe von Methoden, die ein Objekt unterstützen kann, ohne etwas über die Implementierung zu diktieren. Die -Schnittstelle markiert eine klare Grenze zwischen Code, der eine -Methode aufruft, und dem Code, der die -Methode implementiert. In der Informatik ist der Aufrufer von der Implementierung entkoppelt .
In C++ ist die nächste Entsprechung zu einer Schnittstelle eine reine virtuelle Klasse, d. h. eine Klasse, die nur reine virtuelle Methoden und keine anderen Member enthält. Hier sehen Sie ein hypothetisches Beispiel für eine Schnittstelle:
// The following is not actual COM.
// Pseudo-C++:
interface IDrawable
{
void Draw();
};
Die Idee dieses Beispiels ist, dass ein Satz von -Objekten in einer Grafikbibliothek gezeichnet werden kann. Die IDrawable
-Schnittstelle definiert die Vorgänge, die jedes zeichnungsfähige Objekt unterstützen muss. (Gemäß der Konvention beginnen Schnittstellennamen mit "I".) In diesem Beispiel definiert die IDrawable
-Schnittstelle einen einzelnen Vorgang: Draw
.
Alle Schnittstellen sind abstrakt, sodass ein Programm keine instance eines IDrawable
Objekts als solches erstellen konnte. Beispielsweise würde der folgende Code nicht kompiliert.
IDrawable draw;
draw.Draw();
Stattdessen stellt die Grafikbibliothek Objekte bereit, die die IDrawable
-Schnittstelle implementieren. Beispielsweise kann die Bibliothek ein Shape-Objekt zum Zeichnen von Formen und ein Bitmapobjekt zum Zeichnen von Bildern bereitstellen. In C++ wird dies von einer allgemeinen abstrakten Basisklasse geerbt:
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.
};
Die Shape
Klassen und Bitmap
definieren zwei unterschiedliche Typen von zeichnungsfähigen Objekten. Jede Klasse erbt von IDrawable
und stellt eine eigene Implementierung der Draw
-Methode bereit. Natürlich können sich die beiden Implementierungen erheblich unterscheiden. Beispielsweise kann die Shape::Draw
-Methode eine Reihe von Linien rastern, während Bitmap::Draw
ein Array von Pixeln durchblitzt wird.
Ein Programm, das diese Grafikbibliothek verwendet, würde Objekte und Bitmap
durch Zeiger bearbeitenShape
, anstatt oder Bitmap
direkt zu verwenden Shape
IDrawable
.
IDrawable *pDrawable = CreateTriangleShape();
if (pDrawable)
{
pDrawable->Draw();
}
Hier sehen Sie ein Beispiel, das eine Schleife über ein Array von IDrawable
Zeigern führt. Das Array kann eine heterogene Auswahl von Formen, Bitmaps und anderen Grafikobjekten enthalten, solange jedes Objekt im Array erbt IDrawable
.
void DrawSomeShapes(IDrawable **drawableArray, size_t count)
{
for (size_t i = 0; i < count; i++)
{
drawableArray[i]->Draw();
}
}
Ein wichtiger Punkt bei COM ist, dass der aufrufende Code nie den Typ der abgeleiteten Klasse sieht. Anders ausgedrückt: Sie würden niemals eine Variable vom Typ Shape
oder Bitmap
in Ihrem Code deklarieren. Alle Vorgänge für Shapes und Bitmaps werden mithilfe von IDrawable
Zeigern ausgeführt. Auf diese Weise behält COM eine strikte Trennung zwischen Schnittstelle und Implementierung bei. Die Implementierungsdetails der Shape
Klassen und Bitmap
können sich ändern, z. B. um Fehler zu beheben oder neue Funktionen hinzuzufügen, ohne änderungen am aufrufenden Code.
In einer C++-Implementierung werden Schnittstellen mithilfe einer Klasse oder Struktur deklariert.
Hinweis
Die Codebeispiele in diesem Thema sollen allgemeine Konzepte und keine praxisnahe Praxis vermitteln. Das Definieren neuer COM-Schnittstellen geht über den Rahmen dieser Reihe hinaus, aber Sie würden eine Schnittstelle nicht direkt in einer Headerdatei definieren. Stattdessen wird eine COM-Schnittstelle mithilfe einer Sprache namens Interface Definition Language (IDL) definiert. Die IDL-Datei wird von einem IDL-Compiler verarbeitet, der eine C++-Headerdatei generiert.
class IDrawable
{
public:
virtual void Draw() = 0;
};
Wenn Sie mit COM arbeiten, ist es wichtig zu beachten, dass Schnittstellen keine Objekte sind. Dabei handelt es sich um Auflistungen von Methoden, die Objekte implementieren müssen. Mehrere Objekte können dieselbe Schnittstelle implementieren, wie in den Beispielen Shape
und Bitmap
gezeigt. Darüber hinaus kann ein Objekt mehrere Schnittstellen implementieren. Beispielsweise kann die Grafikbibliothek eine Schnittstelle namens ISerializable
definieren, die das Speichern und Laden von Grafikobjekten unterstützt. Betrachten Sie nun die folgenden Klassendeklarationen:
// 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 diesem Beispiel implementiert ISerializable
die Bitmap
-Klasse . Das Programm könnte diese Methode verwenden, um die Bitmap zu speichern oder zu laden. Die Shape
-Klasse implementiert ISerializable
jedoch nicht , sodass diese Funktionalität nicht verfügbar gemacht wird. Das folgende Diagramm zeigt die Vererbungsbeziehungen in diesem Beispiel.
In diesem Abschnitt wurden die konzeptionellen Grundlagen von Schnittstellen untersucht, aber bisher haben wir keinen tatsächlichen COM-Code gesehen. Wir beginnen mit dem ersten, was jede COM-Anwendung tun muss: Initialisieren der COM-Bibliothek.