Поделиться через


Что такое COM-интерфейс?

Если вы знаете C# или Java, интерфейсы должны быть знакомой концепцией. Интерфейс определяет набор методов, которые может поддерживать объект, не диктуя ничего о реализации. Интерфейс отмечает четкую границу между кодом, который вызывает метод, и кодом, реализующим метод . С точки зрения информатики вызывающий объект отделяется от реализации.

Иллюстрация, показывающая границу интерфейса между объектом и приложением

В C++ ближайшим эквивалентом интерфейса является чистый виртуальный класс, то есть класс, который содержит только чистые виртуальные методы и никакие другие члены. Ниже приведен гипотетический пример интерфейса:

// The following is not actual COM.

// Pseudo-C++:

interface IDrawable
{
    void Draw();
};

Идея этого примера заключается в том, что набор объектов в некоторых графических библиотеках можно прорисовать. Интерфейс IDrawable определяет операции, которые должен поддерживать любой рисуемый объект. (По соглашению имена интерфейсов начинаются с "I".) В этом примере IDrawable интерфейс определяет одну операцию: Draw.

Все интерфейсы являются абстрактными, поэтому программе не удалось создать экземпляр объекта как такового IDrawable . Например, следующий код не будет компилироваться.

IDrawable draw;
draw.Draw();

Вместо этого библиотека графики предоставляет объекты, реализующиеIDrawable интерфейс . Например, библиотека может предоставлять объект фигуры для рисования фигур и растровый объект для рисования изображений. В C++ это делается путем наследования от общего абстрактного базового класса:

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

Классы Shape и Bitmap определяют два разных типа рисуемых объектов. Каждый класс наследует от IDrawable и предоставляет собственную реализацию Draw метода . Естественно, эти две реализации могут значительно отличаться. Например, Shape::Draw метод может растеризовать набор строк, а Bitmap::Draw массив пикселей будет вырезать.

Программа, использующий эту графическую библиотеку, будет управлять объектами Shape и Bitmap с помощью IDrawable указателей, а не напрямую использовать Shape указатели или Bitmap .

IDrawable *pDrawable = CreateTriangleShape();

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

Ниже приведен пример циклического перебора массива указателей IDrawable . Массив может содержать разнородный набор фигур, растровых изображений и других графических объектов, если каждый объект в массиве наследует IDrawable.

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

Ключевым моментом com является то, что вызывающий код никогда не видит тип производного класса. Другими словами, вы никогда не объявите переменную типа Shape или Bitmap в коде. Все операции с фигурами и растровыми рисунками выполняются с помощью IDrawable указателей. Таким образом, COM поддерживает строгое разделение между интерфейсом и реализацией. Сведения о Shape реализации классов и Bitmap могут изменяться, например, для исправления ошибок или добавления новых возможностей без каких-либо изменений в вызывающем коде.

В реализации C++ интерфейсы объявляются с помощью класса или структуры.

Примечание

Примеры кода в этом разделе предназначены для передачи общих понятий, а не реальной практики. Определение новых COM-интерфейсов выходит за рамки область этой серии, но вы не будете определять интерфейс непосредственно в файле заголовка. Вместо этого COM-интерфейс определяется с помощью языка, называемого языком определения интерфейса (IDL). IDL-файл обрабатывается компилятором IDL, который создает файл заголовка C++.

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

При работе с COM важно помнить, что интерфейсы не являются объектами. Они представляют собой коллекции методов, которые должны реализовывать объекты . Несколько объектов могут реализовать один и тот же интерфейс, как показано в Shape примерах и Bitmap . Кроме того, один объект может реализовывать несколько интерфейсов. Например, библиотека графики может определить интерфейс с именем ISerializable , поддерживающий сохранение и загрузку графических объектов. Теперь рассмотрим следующие объявления классов:

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

В этом примере Bitmap класс реализует ISerializable. Программа может использовать этот метод для сохранения или загрузки растрового изображения. Однако Shape класс не реализует ISerializable, поэтому он не предоставляет эту функциональность. На следующей схеме показаны отношения наследования в этом примере.

Иллюстрация, показывающая наследование интерфейса с классами фигур и точечных рисунков, указывающими на idrawable, но только растровым рисунком, указывающим на изерисуемый

В этом разделе рассматривается концептуальная основа интерфейсов, но до сих пор мы не видели фактический COM-код. Начнем с первого, что должно сделать любое com-приложение: инициализация библиотеки COM.

Следующая

Инициализация библиотеки COM