实现 CComObject、CComAggObject 和 CComPolyObject

CComObjectCComAggObjectCComPolyObject 的模板类始终是继承链中派生最多的类。 他们负责处理 IUnknown 中的所有方法:QueryInterfaceAddRefRelease。 此外,CComAggObjectCComPolyObject(用于聚合对象)提供内部未知所需的特殊引用计数和 QueryInterface 语义。

是否使用 CComObjectCComAggObjectCComPolyObject 取决于是否声明以下宏之一或者不声明任何宏:

效果
DECLARE_NOT_AGGREGATABLE 请始终使用 CComObject
DECLARE_AGGREGATABLE 如果对象聚合,则使用 CComAggObject;如果不是,则使用 CComObjectCComCoClass 包含此宏,因此,如果类中未声明任何DECLARE_*_AGGREGATABLE 宏,则为默认值。
DECLARE_ONLY_AGGREGATABLE 请始终使用 CComAggObject。 如果未聚合对象,则返回错误。
DECLARE_POLY_AGGREGATABLE 调用 IClassFactory::CreateInstance 时,ATL 将创建 CComPolyObject<CYourClass> 的实例。 在创建过程中,将检查外部未知成员的值。 如果为 NULL,则 IUnknown 为非聚合对象实现。 如果外部未知不为 NULL,则会为聚合对象实现 IUnknown

使用 CComAggObjectCComObject 的优点是实现 IUnknown 针对所创建对象的类型进行了优化。 例如,非聚合对象只需要引用计数,而聚合对象需要内部未知的引用计数和指向外部未知的指针。

使用 CComPolyObject 的优点是,避免在模块中同时使用 CComAggObjectCComObject 处理聚合和非聚合情况。 单个 CComPolyObject 对象处理这两种情况。 这意味着模块中只有一个 vtable 副本和一个函数副本。 如果 vtable 很大,这可以大大减小模块大小。 但是,如果 vtable 较小,则使用 CComPolyObject 可能会导致模块大小略大,因为它未针对聚合或非聚合对象进行优化,如 CComAggObjectCComObject 所示。

另请参阅

ATL COM 对象基础知识
聚合和类工厂宏