看到了吗 C++ [CX]第0部分[N]简介 有关本系列的介绍以及本系列每一篇文章的链接目录。
在本文中,我们将了解静态成员函数以及Windows运行时如何支持它们。Windows运行时引用类型(也称为 托管类 在C++中 运行时类 )可以有静态成员函数。在C++中,用于在运行时类中声明静态成员函数的语法与普通C++类中使用的语法完全相同。为了演示这一点,下面是一个包含一个静态成员函数的运行时类:
public ref class KnownValues sealed { public: static int GetZero() { return 0; }
private: KnownValues(); // This type can't be constructed };
(注意,我们声明了一个私有的默认构造函数,以确保不可能创建此类的实例。如果我们定义一个 ref class
并且不要声明任何构造函数,编译器将为类型提供公共默认构造函数,就像普通C++类一样。可以定义一个可构造且具有静态成员的类型;我们刚刚将此类型设置为不可构造的,以使下面的示例更简单。)
类似地,调用运行时类声明的静态成员函数的语法与普通C++语法完全相同。这是我们的电话 GetZero
:
int x = KnownValues::GetZero();
因此,至少在语法上,C++中的静态成员函数没有什么特别之处。但是,Windows运行时支持静态成员函数的机制值得一提。
静态成员函数的实现
对静态成员函数的调用独立于声明该函数的类的任何实例。静态成员函数没有 this
指针。我们不需要创造一个 KnownValues
对象以调用其 GetZero
静态成员函数。为了允许运行时类具有静态成员函数,我们需要某种方法,这种方法允许我们调用函数而不必首先创建其声明类型的实例。
事实证明,我们已经解决了这个问题 第三部分:在建工程 ,当我们使用激活工厂实现构造函数时。为了总结这篇文章,我们通过以下方式实现了对构造函数的支持:
- 将每个构造函数转换为返回该类型新实例的函数,
- 定义一个称为 工厂接口 ,声明所有这些构造函数,
- 定义一个运行时类,称为 活化厂 ,实现工厂接口,以及
- 提供了一种定义良好的方法来获取任意类型的激活工厂实例。
激活工厂允许我们实现与运行时类相关联的函数,这些函数可以在不首先创建运行时类的实例的情况下调用。一个特定的运行时类只能有一个与之关联的激活工厂,但该激活工厂可以实现多个接口。除了实现零个或多个工厂接口(声明构造函数)之外,激活工厂还可以实现零个或多个工厂接口 静态接口 ,它声明静态成员函数。
我们将实施 KnownValues
使用C++和WRL类型,但是我们不会涉及太多细节;上一篇文章深入讨论了激活工厂,这里没有太多区别。首先,下面是运行时类及其静态接口的IDL声明,非常简单:
[exclusiveto(KnownValues)] [uuid(ca8c9b14-f2a3-4f1e-aa50-49bfa3a5dbd3)] [version(1.0)] interface IKnownValuesStatics : IInspectable { HRESULT GetZero([out] [retval] int* value); }
[static(IKnownValuesStatics, 1.0)] [version(1.0)] runtimeclass KnownValues { }
这个 static
上的属性 KnownValues
指定 IKnownValueStatics
接口是 KnownValues
运行时类。请注意 KnownValues
类型不声明它实现了任何实例接口(即,它的主体是空的)。这是因为 KnownValues
将永远创建运行时类。这个运行时类实际上只是一个用于定义静态成员函数的容器(在C术语中,这称为 静态类 ).
激活工厂的实现也很简单:
class KnownValuesFactory : public ActivationFactory<IKnownValuesStatics> { InspectableClassStatic(RuntimeClass_WRLKnownValuesComponent_KnownValues, BaseTrust)
public: STDMETHODIMP GetZero(int* value) override { *value = 0; return S_OK; } };
ActivatableStaticOnlyFactory(KnownValuesFactory)
请注意,因为我们永远不会创建 KnownValues
,我们实际上不需要定义 KnownValues
C++中的类。我们只需要定义激活工厂,它实现 IKnownValueStatics
静态接口。
所有激活工厂也必须实现 IActivationFactory
接口。这个 ActivationFactory
我们使用的基类模板提供了这个接口的默认实现,它对不可激活的类型做了正确的事情。特定的运行时类既可以激活,也可以具有静态成员函数。在这种情况下,它的激活工厂将实现工厂接口和静态接口。
调用静态成员函数
由于静态成员函数的实现方式与构造函数相同,因此调用静态成员函数的过程与调用构造函数的过程完全相同也就不足为奇了。需要两个步骤:首先,我们需要获取类型的激活工厂,然后我们可以调用函数。要调用的WRL代码 GetZero
具体如下:
HStringReference classId(RuntimeClass_WRLKnownValuesComponent_KnownValues); ComPtr<IKnownValuesStatics> statics; RoGetActivationFactory( classId.Get(), __uuidof(IKnownValuesStatics), reinterpret_cast<void**>(statics.GetAddressOf())); int x = 0; statics->GetZero(&x);
除了简短的省略错误处理之外,这个代码相当于C++的/cx调用。 GetZero
从上面看:
int x = KnownValues::GetZero();