From a065e04d529da1d847b5062a12c46d916408bf32 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 21:46:22 -0500 Subject: update based on https://github.com/mdn/yari/issues/2028 --- files/zh-cn/implementing_queryinterface/index.html | 172 --------------------- 1 file changed, 172 deletions(-) delete mode 100644 files/zh-cn/implementing_queryinterface/index.html (limited to 'files/zh-cn/implementing_queryinterface') diff --git a/files/zh-cn/implementing_queryinterface/index.html b/files/zh-cn/implementing_queryinterface/index.html deleted file mode 100644 index 6fe9761e22..0000000000 --- a/files/zh-cn/implementing_queryinterface/index.html +++ /dev/null @@ -1,172 +0,0 @@ ---- -title: 实现QueryInterface接口 -slug: Implementing_QueryInterface -translation_of: Mozilla/Implementing_QueryInterface ---- -

本文档介绍正确地实现QueryInterface()的方式 

- -

QueryInterface的参考实现

- -
NS_IMETHODIMP
-nsMyImplementation::QueryInterface( REFNSIID aIID, void** aInstancePtr )
-  {
-    NS_ASSERTION(aInstancePtr, "QueryInterface requires a non-NULL destination!");
-      // It's a logic error, not a runtime error, to call me without any place to put my answer!
-
-      // ...but that won't matter when someone calls me wrongly in a non-debug build.
-    if ( !aInstancePtr )
-      return NS_ERROR_NULL_POINTER;
-
-    nsISupports* foundInterface;
-
-    if ( aIID.Equals(nsCOMTypeInfo<nsIX>::GetIID()) )
-      foundInterface = NS_STATIC_CAST(nsIX*, this);
-    else if ( aIID.Equals(nsCOMTypeInfo<nsIY>::GetIID()) )
-      foundInterface = NS_STATIC_CAST(nsIY*, this);
-
-    // ...as many cases as needed...
-
-    else if ( aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID()) )
-      foundInterface = NS_STATIC_CAST(nsISupports*, NS_STATIC_CAST(nsIX*, this));
-        // I (may) have multiple |nsISupports| in me,
-        //  so first I cast to a specific base to avoid ambiguity
-    else
-      foundInterface = 0;
-
-
-    nsresult status;
-    if ( !foundInterface )
-      status = NS_NOINTERFACE;
-    else
-      {
-        NS_ADDREF(foundInterface);
-        status = NS_OK;
-      }
-
-    *aInstancePtr = foundInterface;
-    return status;
-  }
-
-
- -

有什么好处呢?

- -

代码优点:

- - - -

一些替代方案

- -

NS_IMPL_QUERY_INTERFACE[012] 宏

- -

除了nsISupports外,上面的示例还实现了两个{{ mediawiki.external('XP') }} COM接口。NS_IMPL_QUERY_INTERFACE2宏可以为您编写此函数(尽管我很难推荐宏),例如,

- -
NS_IMPL_QUERY_INTERFACE2(nsMyImplementation, nsIX, nsIY)
-                                          // implements |nsMyImplementation::QueryInterface| as above
-
-NS_IMPL_QUERY_INTERFACE1(nsFoo, nsIFoo)   // |nsFoo::QueryInterface| provides |nsIFoo| and |nsISupports|
-NS_IMPL_QUERY_INTERFACE0(nsBar)           // |nsBar::QueryInterface| can only provide an |nsISupports|
-
- -

同样,当仅实现一个附加接口时,可以使用宏NS_IMPL_QUERY_INTERFACE1;当仅实现nsISupports时,可以使用宏NS_IMPL_QUERY_INTERFACE0 。如果使用NS_IMPL_ISUPPORTS*宏,将为您调用这些宏,这些宏提供相应的QueryInterface 实现,以及AddRefRelease

- -

调用继承的 QueryInterface

- -

有时,您只是将一个或两个新接口添加到已经支持许多其他接口的实现中。在这种情况下,在测试了所关心的特定IID之后,您可能希望调用底层实现。这节省了代码空间并降低了复杂性。下面的代码突出显示了这些差异。

- -
class nsMyImplmentation : public nsBaseImplementation, public nsIX, public nsIY { ... };
-
-NS_IMETHODIMP
-nsMyImplementation::QueryInterface( REFNSIID aIID, void** aInstancePtr )
-    /*
-      I just add the interfaces |nsIX| and |nsIY|.
-      My base class |nsBaseImplementation| provides all the rest.
-    */
-  {
-    NS_ASSERTION(aInstancePtr, "QueryInterface requires a non-NULL destination!");
-
-    if ( !aInstancePtr )
-      return NS_ERROR_NULL_POINTER;
-
-    nsISupports* foundInterface;
-
-    if ( aIID.Equals(nsCOMTypeInfo<nsIX>::GetIID()) )
-      foundInterface = NS_STATIC_CAST(nsIX*, this);
-    else if ( aIID.Equals(nsCOMTypeInfo<nsIY>::GetIID()) )
-      foundInterface = NS_STATIC_CAST(nsIY*, this);
-    // Note: Don't check for |nsISupports|; |nsBaseImplementation| will do that for me.
-    else
-      foundInterface = 0;
-
-
-    nsresult status;
-    if ( !foundInterface )
-        // OK, _I_ didn't find an interface.  Maybe my base class can.
-      status = nsBaseImplementation::QueryInterface(aIID, &foundInterface);
-    else
-      {
-        NS_ADDREF(foundInterface);
-        status = NS_OK;
-      }
-
-    *aInstancePtr = foundInterface;
-    return status;
-  }
-
- -

请注意,如果 base实现 的 QueryInterface找到了适当的接口,则你的QueryInterface 不能 AddRef 它。这反映在上面的代码中。
-
- 这种技术之所以有效,是因为 nsBaseImplementation 已经是一个可以单独使用的完整类。当你从几个完整的类派生时,这种技术不太合适;但如果您对顺序敏感,则仍然可以使用它,例如,

- -
// ...
-    nsresult status;
-    if ( !foundInterface )
-      {
-        // OK, ask |nsBase1Imp| first, because I want _it_ to be the one true |nsISupports|.
-        status = nsBase1Imp::QueryInterface(aIID, &foundInterface);
-
-        if ( !foundInterface )
-          status = nsBase2Imp::QueryInterface(aIID, &foundInterface);
-
-        if ( !foundInterface )
-          status = nsBase3Imp::QueryInterface(aIID, &foundInterface);
-      }
-    else
-      {
-        NS_ADDREF(foundInterface);
-        status = NS_OK;
-      }
-    // ...
-
- -

如果您的任何基类参与真正的聚合,那么要把正确的事情做好 即使不是不可能,也是很困难的。您将不能在聚合对象上获得对 QueryInterface 的调用,这可能会返回错误的接口。这也是一个需要特别避免 聚合和复杂的层次结构 的原因。

- -

NS_GET_IID 宏

- -

您可以使用·NS_GET_IID 宏,而不是键入完整的GetIID 表达式。一般来说,我不赞成宏,除非在不同的情况下宏必须扩展为不同的文本,例如,不同的平台,调试与非调试,等等。在这种情况下,宏是必不可少的。在其他情况下,宏可能会帮助一些人,但通常会给其他人带来模糊的问题。它们总是使程序源更加脆弱。在这种情况下,宏只是为了方便起见,所以我不推荐它,但我确实提供了它作为替代。

- -
// ...
-    if ( aIID.Equals(NS_GET_IID(nsIX)) )
-      foundInterface = NS_STATIC_CAST(nsIX*, this);
-    else if ( aIID.Equals(NS_GET_IID(nsIY)) )
-      foundInterface = NS_STATIC_CAST(nsIY*, this);
-
-    // ...as many cases as needed...
-
-    else if ( aIID.Equals(NS_GET_IID(nsISupports)) )
-    // ...
- -

Thanks

- -

特别感谢 Heikki ToivonenChris WatersonJohn Bandhauer 提供的宝贵反馈,这些反馈极大地改进了这里提供的实现

-- cgit v1.2.3-54-g00ecf