什么是 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.
};

ShapeBitmap 类定义两种不同类型的可绘制对象。 每个类继承自 IDrawable ,并提供其自己的 方法实现 Draw 。 当然,这两种实现可能会大相径庭。 例如, Shape::Draw 方法可能会对一组线条进行光栅化,而 Bitmap::Draw 会照亮一个像素数组。

使用此图形库的程序将通过指针操作 ShapeBitmap 对象 IDrawable ,而不是直接使用 ShapeBitmap 指针。

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 在接口和实现之间保持严格的分离。 和 Bitmap 类的Shape实现详细信息可以更改(例如,修复 bug 或添加新功能),无需更改调用代码。

在 C++ 实现中,使用类或结构声明接口。

注意

本主题中的代码示例旨在传达一般概念,而不是实际做法。 定义新的 COM 接口超出了本系列的范围,但你不会直接在头文件中定义接口。 而是使用名为接口定义语言 (IDL) 的语言定义 COM 接口。 IDL 文件由 IDL 编译器处理,该编译器生成 C++ 头文件。

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

使用 COM 时,请务必记住接口不是对象。 它们是对象必须实现的方法集合。 多个对象可以实现相同的接口,如 和 Bitmap 示例所示Shape。 此外,一个对象可以实现多个接口。 例如,图形库可以定义一个名为 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,但仅位图指向 iserializable

本部分介绍了接口的概念基础,但到目前为止,我们还没有看到实际的 COM 代码。 我们将从任何 COM 应用程序必须执行的第一件事开始:初始化 COM 库。

下一步

初始化 COM 库