类型系统概述 (C++/CX)
通过使用 Windows 运行时体系结构,可以使用 C++/WinRT、C++/CX、Visual Basic、Visual C# 和 JavaScript 来编写应用和组件。 它们可以直接访问 Windows API,并与其他 Windows 运行时应用和组件进行互操作。 用 C++ 编写的通用 Windows 平台 (UWP) 应用编译为直接在 CPU 中执行的本机代码。 用 C# 或 Visual Basic 编写的 UWP 应用编译为 Microsoft 中间语言 (MSIL) 并在公共语言运行时 (CLR) 中执行。 用 JavaScript 编写的 UWP 应用在 JavaScript 运行时环境中执行。 Windows 运行时操作系统组件本身用 C++ 编写并作为本机代码运行。 所有这些组件和 UWP 应用都直接通过 Windows 运行时应用程序二进制接口 (ABI) 通信。
为了能够以现代 C++ 惯例支持 Windows 运行时,Microsoft 创建了 C++/CX 语言扩展。 C++/CX 提供基本 Windows 运行时类型的内置基类型和实现。 这些类型使得 C++ 应用和组件能够通过 ABI 与用其他语言编写的应用通信。 C++/CX 应用可以使用任何 Windows 运行时类型。 它们还可以创建类、结构、接口以及其他用户定义类型供其他 UWP 应用和组件使用。 只要没有公共可访问性,用 C++/CX 编写的 UWP 应用也能使用常规 C++ 类和结构。
有关 C++/CX 语言投影的深度讨论以及它在后台如何工作,请参阅以下博客帖子:
注意
虽然 C++/CX 仍受支持,但对于新 Windows 运行时应用和组件,建议改为使用 C++/WinRT。 它旨在为你提供对新式 Windows API 的优先访问权限。 虽然名称不同,但 C++/WinRT 仅使用没有扩展的标准 C++17。 它使用仅标头库为 Windows 运行时 API 实现 C++ 语言投影。 从版本 1803 (10.0.17134.0) 起,C++/WinRT 在 Windows SDK 中提供。
Windows 元数据 (.winmd) 文件
当你编译用 C++ 编写的 UWP 应用时,编译器生成本机代码的可执行文件,以及包含公共 Windows 运行时类型(包括类、结构、枚举、接口、参数化接口和委托)描述的单独 Windows 元数据 (.winmd
) 文件。 元数据的格式类似于在 .NET Framework 程序集中使用的格式。 在 C++ 组件中,.winmd
文件只包含元数据;可执行代码位于单独的文件中。 Windows 附带的 Windows 运行时组件使用这种安排。 .winmd
文件名必须与源代码中的根命名空间的前缀匹配或为该前缀。 (对于 .NET Framework 语言,.winmd
文件同时包含代码和元数据,正如一个 .NET Framework 程序集。)
.winmd
文件中的元数据表示你的代码的已发布图面。 发布类型对其他 UWP 应用可见,无论这些应用是用什么语言编写的。 元数据或你的发布代码都只能包含 Windows 运行时类型系统指定的类型。 不能发布特定于 C++ 的语言构造(如规则类、数组、模板或 C++ 标准库 (STL) 容器)。 JavaScript 或 C# 客户端应用不知道如何处理它们。
类型或方法在元数据中是否可见取决于应用于它们的可访问性修饰符。 若要可见,必须在命名空间中声明类型,而且必须声明为 public
。 允许在你的代码中将非 public
ref class
作为内部帮助程序类型,它在元数据中正好不可见。 即使在 public ref class
中,也不一定所有的成员都是可见的。 下表列出了 public ref class
中 C++访问说明符与 Windows 运行时元数据可见性之间的关系:
在元数据中发布 | 未在元数据中发布 |
---|---|
public |
private |
protected |
internal |
public protected |
private protected |
可以使用“对象浏览器”查看 .winmd
文件的内容。 在 Windows.winmd
文件中已找到 Windows 附带的 Windows 运行时组件。 default.winmd
文件包含 C++/CX 中使用的基本类型,platform.winmd
包含来自 Platform
命名空间的类型。 默认情况下,这三个 .winmd
文件包括在 UWP 应用的每个 C++ 项目中。
提示
Platform::Collections
namespace 中的类型没有出现在 .winmd
文件中,因为它们不是公共类型。 它们是 Windows::Foundation::Collections
中定义的接口的专用 C++ 特定实现。 用 JavaScript 或 C# 编写的 Windows 运行时应用不知道 Platform::Collections::Vector
类是什么,但是它可以使用 Windows::Foundation::Collections::IVector
。 Platform::Collections
类型是在 collection.h
中定义的。
C++/CX 中的 Windows 运行时类型系统
以下各节介绍 Windows 运行时类型系统的主要功能,以及 C++/CX 如何支持它们。
命名空间
必须在命名空间内声明所有 Windows 运行时类型,Windows API 本身是按命名空间组织的。 .winmd
文件必须具有与根命名空间相同的名称。 例如,名为 A.B.C.MyClass
的类只有在名为 A.winmd
、A.B.winmd
或 A.B.C.winmd
的元数据文件中定义后才能被实例化。 DLL 的名称不必与 .winmd
文件名一致。
Windows API 本身已重创为按命名空间组织的分解类库。 所有 Windows 运行时组件都是在 Windows.*
命名空间中声明的。
有关详细信息,请参阅命名空间和类型可见性。
基本类型
Windows 运行时定义以下基本类型:UInt8
、Int16
、UInt16
、Int32
、UInt32
、Int64
、UInt64
、Single
、Double
、Char16
、Boolean
和 String
。 C++/CX 支持其默认命名空间中的基本数值类型,如 uint16
、uint32
、uint64
、int16
、int32
、int64
、float32
、float64
和 char16
。 Boolean
和 String
也是在 Platform
命名空间中定义的。
C++/CX 还定义 uint8
,它等效于 unsigned char
(在 Windows 运行时中不受支持,也不能用于公共 API)。
通过将基本类型包装在 Platform::IBox
接口中,可以使其可为空。 有关更多信息,请参见 值类和结构中定义的接口的私有 C++ 特定实现。
有关基础类型的更多信息,请参见 基础类型
字符串
Windows 运行时字符串是 16 位 UNICODE 字符的一个不可变序列。 Windows 运行时字符串表现为 Platform::String^
。 此类为字符串构造、处理和在 wchar_t
间来回转换提供方法。
有关更多信息,请参见 字符串中定义的接口的私有 C++ 特定实现。
数组
Windows 运行时支持任何类型的一维数组。 不支持数组的数组。 在 C++/CX 中,Windows 运行时数组表现为 Platform::Array
类。
有关详细信息,请参阅 Array
和 WriteOnlyArray
。
ref class
和 ref struct
类型
Windows 运行时类在 C++/CX 中表现为 ref class
或 ref struct
类型,因为它是通过引用复制的。 ref class
和 ref struct
对象的内存管理通过引用计数透明地处理。 当对对象的最后引用超出范围时,对象被销毁。 ref class
或 ref struct
类型可以:
作为成员构造函数、方法、属性和事件而包含。 这些成员可以具有
public
、private
、protected
或internal
可访问性。可以包含专用嵌套的
enum
、struct
或class
定义。可直接从基类继承,并且可以实现任意数量的接口。 所有
ref class
对象都可以隐式转换为Platform::Object
类,并且可重写其虚拟方法,例如Object::ToString
。
为防止进一步派生,必须将具有公共构造函数的 ref class
声明为 sealed
。
有关更多信息,请参见 Ref 类和结构
value class
和 value struct
类型
value class
或 value struct
表示基本数据结构,它们只包含字段,这可能是 value class
类型、value struct
类型或类型 Platform::String^
。 value struct
和 value class
对象是通过值复制的。
通过将 value struct
包装在 IBox
接口中,可以使其可为空。
有关更多信息,请参见 值类和结构中定义的接口的私有 C++ 特定实现。
分部类
分部类功能可使你对多个文件定义一个类。 这样使代码生成工具(如 XAML 编辑器)能够在不影响你所编辑的其他文件的情况下修改一个文件。
有关更多信息,请参见 分部类
属性
属性是任何 Windows 运行时类型的一个公共数据成员。 它是通过 property
关键字声明和定义的。 属性作为一个 get
/set
方法对实现。 客户端代码访问属性,就好像属性是一个公共字段。 不需要任何自定义 get
或 set
代码的属性称为“普通属性”,无需显式 get
或 set
方法即可声明它们。
有关详细信息,请参阅 属性。
C++/CX 中的 Windows 运行时集合
Windows 运行时为每种语言按自己的方式实现的集合类型定义一组接口。 C++/CX 在 Platform::Collections::Vector
类、Platform::Collections::Map
类中提供实现,并提供其他相关具体集合类型,这些类型与它们的 C++ 标准库对等项兼容。
有关详细信息,请参阅集合。
模板 ref class
类型
private
和 internal
访问可以进行模板化和专用化的 ref class
类型。
有关更多信息,请参见 模板 ref 类中定义的接口的私有 C++ 特定实现。
接口
Windows 运行时接口定义了一组公共属性、方法和事件,如果一个 ref class
或 ref struct
类型继承自该接口,就必须实现这些属性、方法和事件。
有关详细信息,请参阅接口。
枚举
Windows 运行时中的 enum class
类型类似于 C++ 中的作用域 enum
。 基本类型是 int32
(除非应用 [标志] 特性,此情况下的基础类型是 uint32
)。
有关更多信息,请参见 枚举中定义的接口的私有 C++ 特定实现。
委托
Windows 运行时中的委托类似于 C++ 中的 std::function
对象。 它是一个特殊的 ref class
类型,用于调用具有兼容签名的客户端提供的函数。 委托通常在 Windows 运行时中用作事件类型。
有关详细信息,请参阅委托。
例外
在 C++/CX 中,可以捕获自定义异常类型、std::exception
类型和 Platform::Exception
类型。
有关更多信息,请参见 异常中定义的接口的私有 C++ 特定实现。
事件
事件是其类型为委托类型的 ref class
或 ref struct
中的公共成员。 事件只能被调用,即,被所属类触发。 但是,客户端代码可以提供自己的事件处理程序函数,并在所属类触发事件时被调用。
有关详细信息,请参阅事件。
强制转换
C++/CX 支持标准 C++ 强制转换运算符 static_cast
、dynamic_cast
和 reinterpret_cast
,以及特定于 C++/CX 的 safe_cast
运算符。
有关更多信息,请参见 强制转换中定义的接口的私有 C++ 特定实现。
装箱
装箱变量是包装在引用类型中的值类型。 在需要引用语义的情况下使用装箱变量。
有关更多信息,请参见 装箱中定义的接口的私有 C++ 特定实现。
属性
特性是可以应用于任何 Windows 运行时类型或类型成员的元数据值。 可以在运行时检查特性。 Windows 运行时在 Windows::Foundation::Metadata
命名空间中定义了一组常见特性。 在此版本中,Windows 运行时不支持公共接口上的用户定义的特性。
API 弃用
可以使用由 Windows 运行时系统类型所用的同一特性将公共 API 标记为已弃用。
有关详细信息,请参阅弃用类型和成员。