通过 C++/WinRT 使用 API

如果 API 位于 Windows 命名空间中

这是你使用 Windows 运行时 API 最常见的情况。 对于元数据中定义的 Windows 命名空间中的每个类型,C++/WinRT 都定义了 C++ 友好等效项(称为投影类型 )。 投影类型具有与 Windows 类型相同的完全限定名称,但使用 C++ 语法放置于 C++ winrt 命名空间中。 例如,Windows::Foundation::Uri 作为 winrt::Windows::Foundation::Uri 投影到 C++/WinRT。

以下是一个简单的代码示例。 若要将以下代码示例直接复制并粘贴到 Windows 控制台应用程序 (C++/WinRT) 项目的主源代码文件中,请先在项目属性中设置“不使用预编译的标头” 。

// main.cpp
#include <winrt/Windows.Foundation.h>

using namespace winrt;
using namespace Windows::Foundation;

int main()
{
    winrt::init_apartment();
    Uri contosoUri{ L"http://www.contoso.com" };
    Uri combinedUri = contosoUri.CombineUri(L"products");
}

包含的标头 winrt/Windows.Foundation.h 是 SDK 的一部分,可在文件夹 %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt\ 内找到。 该文件夹中的标头包含投影到 C++/WinRT 中的 Windows 命名空间类型。 在此示例中,winrt/Windows.Foundation.h 包含 winrt::Windows::Foundation::Uri ,它是运行时类 Windows::Foundation::Uri 的投影类型。

提示

如果希望使用来自 Windows 命名空间的类型,请包括与该命名空间对应的 C++/WinRT 标头。 using namespace 指令是可选的,不过这种指令很方便。

在上述代码示例中,在初始化 C++/WinRT 后,我们将通过其公开记录的构造函数之一(本示例中为 Uri(字符串) )堆叠分配 winrt::Windows::Foundation::Uri 投影类型的值。 这是最常见的用例,也是一般情况下你所要做的全部工作。 在有了 C++/WinRT 投影类型值后,你可以将其视为实际 Windows 运行时类型的实例,因为它具有所有相同的成员。

事实上,该投影值是一个代理;它本质上只是支持对象的智能指针。 投影值的构造函数调用 RoActivateInstance 来创建 Windows 运行时支持类(本例中为 Windows.Foundation.Uri )的实例,并将该对象的默认接口存储在新投影值内。 如下所示,你对投影值的成员的调用实际上通过智能指针代理给支持对象;这是发生状态变化的地方。

The projected Windows::Foundation::Uri type

当 contosoUri 值超出范围时,它将自行销毁,并将其引用发布到默认接口。 如果该引用是对支持 Windows 运行时 Windows.Foundation.Uri 对象的最后一个引用,支持对象也会自行销毁。

提示

投影类型 是出于使用运行时类的 API 针对运行时类的包装器。 投影接口 是针对 Windows 运行时接口的包装器。

C++/WinRT 投影标头

若要使用 C++/WinRT 的 Windows 命名空间 API,你应使用来自 %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt 文件夹的标头。 下级命名空间中的类型在其直接父命名空间中引用类型是很常见的。 因此,每个 C++/WinRT 投影标头将自动包括其父命名空间标头文件;因此你不需要 明确包括它。 不过,这样做也不会出现错误。

例如,对于 Windows::Security::Cryptography::Certificates 命名空间,等效的 C++/WinRT 类型定义驻留在 winrt/Windows.Security.Cryptography.Certificates.h 中。 Windows::Security::Cryptography::Certificates 中的类型需要父 Windows::Security::Cryptography 命名空间中的类型;该命名空间中的类型可能需要其自己的父 Windows::Security 中的类型。

因此,当你包括 winrt/Windows.Security.Cryptography.Certificates.h 时,该文件反之将包括 winrt/Windows.Security.Cryptography.h;且 winrt/Windows.Security.Cryptography.h 将包括 winrt/Windows.Security.h。 这就是跟踪停止的位置,因为没有 winrt/Windows.h。 此可传递包含过程在第二级命名空间停止。

此过程间接包括为在父命名空间中定义的类提供必要的声明 和实现 的标头文件。

一个命名空间中类型的成员可以引用其他无关命名空间中的一个或多个类型。 为了让编译器能够成功编译这些成员定义,编译器需要查看所有这些类型关闭的类型声明。 因此,每个 C++/WinRT 投影标头均包括它需要声明 任何依赖类型的命名空间标头。 与父命名空间不同,此过程不 拉入所引用类型的实现 。

 重要

当你希望实际使用 在无关命名空间中声明的类型(实例化、调用方法等)时,你必须包括该类型的相应的命名空间标头文件。 仅自动包括声明 ,没有实现 。

例如,如果你仅包括 winrt/Windows.Security.Cryptography.Certificates.h,则会导致声明从这些命名空间(等等,间接)拉入。

  • Windows.Foundation
  • Windows.Foundation.Collections
  • Windows.Networking
  • Windows.Storage.Streams
  • Windows.Security.Cryptography

换言之,某些 API 在你包括的标头中进行了前向声明。 但它们的定义在你尚未包括的标头中。 因此,如果你随后调用 Windows::Foundation::Uri::RawUri ,那么你会收到指示成员未定义的链接器错误。 解决方法是明确 #include <winrt/Windows.Foundation.h>一般情况下,当你看到此类链接器错误时,应包括为该 API 的命名空间命名的标头,并重新生成。

通过对象、接口或通过 ABI 访问成员

使用 C++/WinRT 投影,Windows 运行时类的运行时表示形式将只是基础 ABI 接口。 不过,为方便起见,你可以通过类作者预期的方式根据类编码。 例如,你可以调用 Uri 的 ToString 方法,就像它是该类的方法(实际上,再深入一层,它是单独的 IStringable 接口上的方法)。

WINRT_ASSERT 是宏定义,并且扩展到 _ASSERTE。

Uri contosoUri{ L"http://www.contoso.com" };
WINRT_ASSERT(contosoUri.ToString() == L"http://www.contoso.com/"); // QueryInterface is called at this point.

这种便利是通过对相应接口的查询实现的。 不过始终在你的控制范围内。 你可以通过自己检索 IStringable 接口并直接使用它来放弃一点便利,从而提高一点性能。

在下方的代码示例中,你在运行时获取实际的 IStringable 接口指针(通过一次性查询)。 此后,你对 ToString 的调用是直接的,并且避免进一步调用 QueryInterface。

...
IStringable stringable = contosoUri; // One-off QueryInterface.
WINRT_ASSERT(stringable.ToString() == L"http://www.contoso.com/");

如果你知道你将在同一个接口调用多个方法,你可能会选择使用此技巧。

顺便说一下,如果你确实希望访问 ABI 级别的成员,那么你可以这样做。

下方的代码示例显示了如何操作,实现 C++/WinRT 与 ABI 之间的互操作中还提供了更多详细信息和代码示例。

#include <Windows.Foundation.h>
#include <unknwn.h>
#include <winrt/Windows.Foundation.h>
using namespace winrt::Windows::Foundation;

int main()
{
    winrt::init_apartment();
    Uri contosoUri{ L"http://www.contoso.com" };

    int port{ contosoUri.Port() }; // Access the Port "property" accessor via C++/WinRT.

    winrt::com_ptr<ABI::Windows::Foundation::IUriRuntimeClass> abiUri{
        contosoUri.as<ABI::Windows::Foundation::IUriRuntimeClass>() };
    HRESULT hr = abiUri->get_Port(&port); // Access the get_Port ABI function.
}

延迟初始化

在 C++/WinRT 中,每个投影的类型都有一个特殊的 C++/WinRT std::nullptr_t 构造函数。 除了该构造函数,所有其他投影类型的构造函数(包括默认的构造函数)都会导致系统创建一个支持的 Windows 运行时对象,并为你提供它的智能指针。 因此,该规则适用于使用默认构造函数的任何地方,例如未初始化的本地变量、未初始化的全局变量以及未初始化的成员变量。

另一方面,如果你想要构造投影类型的变量,而无需它反过来构造支持的 Windows 运行时对象(以便你可以延迟该工作),你可以这样做。 使用该特殊 C++/WinRT std::nullptr_t 构造函数(C++/WinRT 投影已将它插入每个运行时类中)声明你的变量或字段

在下面的代码示例中,我们将该特殊构造函数与 m_gamerPicBuffer 配合使用。

#include <winrt/Windows.Storage.Streams.h>
using namespace winrt::Windows::Storage::Streams;

#define MAX_IMAGE_SIZE 1024

struct Sample
{
    void DelayedInit()
    {
        //分配实际缓冲区,延迟初始化
        m_gamerPicBuffer = Buffer(MAX_IMAGE_SIZE);
    }

private:
    Buffer m_gamerPicBuffer{ nullptr };//使用该特殊 C++/WinRT std::nullptr_t 构造函数(C++/WinRT 投影已将它插入每个运行时类中)声明你的变量或字段
};

int main()
{
    winrt::init_apartment();
    Sample s;
    // ...
    s.DelayedInit();
}

除 std::nullptr_t 构造函数以外的投影类型上的所有构造函数都将导致创建后备 Windows 运行时对象。 std::nullptr_t 构造函数本质上不执行任何操作。 它预期投影对象会在后续时间初始化。 因此,不论运行时类是否具有默认的构造函数,你都可以使用此技巧实现有效的延迟初始化。

此注意事项会影响在其中调用默认构造函数的其他位置(如在向量和映射中)

请考虑此代码示例,对它需要“空白应用(C++/WinRT)” 项目。

std::map<int, TextBlock> lookup;
lookup[2] = value;

进行分配会创建新 TextBlock ,然后立即使用 value 覆盖它。 下面是补救措施。

std::map<int, TextBlock> lookup;
lookup.insert_or_assign(2, value);

另请参阅默认构造函数如何影响集合。

不要错误地延迟初始化

请注意不要错误地调用 std:: nullptr_t 构造函数。 编译器的冲突解决偏向于它而非工厂构造函数。 例如,请考虑这两个运行时类定义。

idl

// GiftBox.idl
runtimeclass GiftBox
{
    GiftBox();
}

// Gift.idl
runtimeclass Gift
{
    Gift(GiftBox giftBox); // You can create a gift inside a box.
}

假设我们想要构造一个不在盒子内的 Gift(使用未初始化的 GiftBox 构造的 Gift)。 首先,让我们看看错误的做法。 我们知道有一个接受 GiftBox 的 Gift 构造函数。 但是,如果想要传递 null GiftBox(通过统一初始化调用 Gift 构造函数,如下所示),则不会获得我们想要的结果 。

// These are *not* what you intended. Doing it in one of these two ways
// actually *doesn't* create the intended backing Windows Runtime Gift object;
// only an empty smart pointer.

Gift gift{ nullptr };
auto gift{ Gift(nullptr) };

在此处得到的是一个未初始化的 Gift。 你无法通过未初始化的 GiftBox 得到 Gift。 下面是正确 的做法。

// Doing it in one of these two ways creates an initialized
// Gift with an uninitialized GiftBox.

Gift gift{ GiftBox{ nullptr } };
auto gift{ Gift(GiftBox{ nullptr }) };

在不正确的示例中,传递 nullptr 文本会以有利于延迟初始化构造函数的方式解析。 若要以有利于工厂构造函数的方式解析,参数的类型必须是 GiftBox。 仍然可以选择传递一个显式延迟初始化 GiftBox,如正确的示例中所示。

下一个示例也正确 ,因为参数的类型为 GiftBox,而不是 std:: nullptr_t

GiftBox giftBox{ nullptr };
Gift gift{ giftBox }; // Calls factory constructor.

仅当传递 nullptr 文本时才会引起多义性。

不要错误地复制构造。

此警告类似于上面的不要错误地延迟初始化部分中所述的警告。

除了该延迟初始化构造函数之外,C++/WinRT 投影也会将复制构造函数注入到每个运行时类中。 它是一个单参数构造函数,接受与所构造对象相同的类型。 生成的智能指针指向其构造函数参数指向的同一后备 Windows 运行时对象。 结果是两个智能指针对象指向同一后备对象。

下面是我们将在代码示例中使用的运行时类定义。

idl

// GiftBox.idl
runtimeclass GiftBox
{
    GiftBox(GiftBox biggerBox); // You can place a box inside a bigger box.
}

假设我们想要在一个较大的 GiftBox 内构造 GiftBox

GiftBox bigBox{ ... };

// These are *not* what you intended. Doing it in one of these two ways
// copies bigBox's backing-object-pointer into smallBox.
// The result is that smallBox == bigBox.

GiftBox smallBox{ bigBox };
auto smallBox{ GiftBox(bigBox) };

正确的做法是显式调用激活工厂。

GiftBox bigBox{ ... };

// These two ways call the activation factory explicitly.

GiftBox smallBox{
    winrt::get_activation_factory<GiftBox, IGiftBoxFactory>().CreateInstance(bigBox) };
auto smallBox{
    winrt::get_activation_factory<GiftBox, IGiftBoxFactory>().CreateInstance(bigBox) };

如果在 Windows 运行时组件中实现此 API

无论你是自行创作该组件,还是该组件来自供应商,本部分均适用。

在应用程序项目中,引用 Windows 运行时组件的 Windows 运行时元数据 (.winmd) 文件,然后生成。 在生成过程中,cppwinrt.exe 工具生成标准 C++ 库,该库全面描述(或投影)该组件的 API 接口。 换言之,生成的库包含该组件的投影类型。

然后,与 Windows 命名空间类型一样,你只需包含标头并通过其构造函数之一构造投影类型。 应用程序项目的启动代码注册运行时类,然后投影类型的构造函数调用 RoActivateInstance 来激活引用组件中的运行时类。

#include <winrt/ThermometerWRC.h>

struct App : implements<App, IFrameworkViewSource, IFrameworkView>
{
    ThermometerWRC::Thermometer thermometer;
    ...
};

如果在使用的项目中实现 API

本部分中的代码示例摘自 XAML 控件;绑定到 C++/WinRT 属性主题。 请查看该主题了解更多详细信息、代码和演练,其中该演练描述了使用在采用它的同一项目中实现的运行时类的情况。

通过 XAML UI 使用的类型必须为运行时类,即使其位于与 XAML 相同的项目中。 在这种情况下,从运行时类的 Windows 运行时元数据 (.winmd) 中生成一个投影类型。 同样,你还可包含一个标头,但随后可选择 C++/WinRT 版本 1.0 或版本 2.0 方法来构造该运行时类的实例。 版本 1.0 方法使用 winrt::make;版本 2.0 方法被称作统一构造。 让我们来逐一查看。

使用 winrt::make 进行构造

让我们从默认方法(C++/WinRT 版本 1.0)开始,因为最好至少要熟悉该模式。 通过其 std::nullptr_t 构造函数构造投影类型。 该构造函数不执行任何初始化,所以你接下来必须通过 winrt::make 帮助程序函数向该实例分配一个值,同时传递任何必要的构造函数参数。 在使用代码的同一项目中实现的运行时类无需进行注册,且无需通过 Windows 运行时/COM 激活进行实例化。

有关完整演练,请参阅 XAML 控件;绑定到 C++/WinRT 属性。 本部分显示了摘自该演练的内容。

// MainPage.idl
import "BookstoreViewModel.idl";
namespace Bookstore
{
    runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
    {
        BookstoreViewModel MainViewModel{ get; };
    }
}

// MainPage.h
...
struct MainPage : MainPageT<MainPage>
{
    ...
    private:
        Bookstore::BookstoreViewModel m_mainViewModel{ nullptr };
};
...

// MainPage.cpp
...
#include "BookstoreViewModel.h"

MainPage::MainPage()
{
    m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>();//​通过 winrt::make 帮助程序函数向该实例分配一个值,同时传递任何必要的构造函数参数。
​    ...
}

统一构造

在 C++/WinRT 版本 2.0 及更高版本中,有一种优化的构造形式可供你使用,它被称作“统一构造”(请参见 C++/WinRT 2.0 中的新增功能和更改)。

有关完整演练,请参阅 XAML 控件;绑定到 C++/WinRT 属性。 本部分显示了摘自该演练的内容。

若要使用统一构造而不是 winrt::make,你需要一个激活工厂。 要生成激活工厂,一种好的方式是向 IDL 添加构造函数。

// MainPage.idl
import "BookstoreViewModel.idl";
namespace Bookstore
{
    runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
    {
        MainPage();
        BookstoreViewModel MainViewModel{ get; };
    }
}

然后,在 MainPage.h 中声明和初始化 m_mainViewModel;此操作只需一步,如下所示。

// MainPage.h
...
struct MainPage : MainPageT<MainPage>
{
    ...
    private:
        Bookstore::BookstoreViewModel m_mainViewModel;
        ...
    };
}
...

接下来,在 MainPage.cpp 中的 MainPage 构造函数中,无需使用代码 m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>();

有关统一构造的详细信息,请参阅选择加入统一构造和直接实现访问。

实例化和返回投影类型和接口

以下投影类型和实例的示例可能类似于使用的项目。 请记住,投影类型(如此示例中的一种投影类型)是工具生成的,而不是你自己创作的内容。

struct MyRuntimeClass : MyProject::IMyRuntimeClass, impl::require<MyRuntimeClass,
    Windows::Foundation::IStringable, Windows::Foundation::IClosable>

MyRuntimeClass 是投影类型;投影接口包括 IMyRuntimeClass 、IStringable 和 IClosable 。 本主题已展示你可用来实例化投影类型的不同方法。 以下是提醒和总结,这里使用 MyRuntimeClass 作为示例。

// The runtime class is implemented in another compilation unit (it's either a Windows API,
// or it's implemented in a second- or third-party component).
MyProject::MyRuntimeClass myrc1;

// The runtime class is implemented in the same compilation unit.
MyProject::MyRuntimeClass myrc2{ nullptr };
myrc2 = winrt::make<MyProject::implementation::MyRuntimeClass>();
  • 你可以访问一个投影类型的所有接口的成员。
  • 可以将投影类型返回到调用方。
  • 投影类型和接口派生自 winrt::Windows::Foundation::IUnknown 。 因此,你可以对投影类型或接口调用 IUnknown::as 以查询其他也可使用或返回到调用方的投影接口。 as 成员函数的工作方式类似于 QueryInterface 。
void f(MyProject::MyRuntimeClass const& myrc)
{
    myrc.ToString();
    myrc.Close();
    IClosable iclosable = myrc.as<IClosable>();
    iclosable.Close();
}

激活工厂

创建 C++/WinRT 对象的便利直接的方式如下所示。

using namespace winrt::Windows::Globalization::NumberFormatting;
...
CurrencyFormatter currency{ L"USD" };

不过,有时你可能想要自己创建激活工厂,然后在方便时从其创建对象。

下面的一些示例向你展示了如何使用 winrt::get_activation_factory 函数模板来实现此目的。

using namespace winrt::Windows::Globalization::NumberFormatting;
...
auto factory = winrt::get_activation_factory<CurrencyFormatter, ICurrencyFormatterFactory>();
CurrencyFormatter currency = factory.CreateCurrencyFormatterCode(L"USD");
using namespace winrt::Windows::Foundation;
...
auto factory = winrt::get_activation_factory<Uri, IUriRuntimeClassFactory>();
Uri uri = factory.CreateUri(L"http://www.contoso.com");

上面两个示例中的类是来自 Windows 命名空间的类型。 在接下来的示例中,ThermometerWRC::Thermometer 是在 Windows 运行时组件中实现的自定义类型。

auto factory = winrt::get_activation_factory<ThermometerWRC::Thermometer>();
ThermometerWRC::Thermometer thermometer = factory.ActivateInstance<ThermometerWRC::Thermometer>();

成员/类型多义性

当成员函数的名称与类型的名称相同时,会产生多义性。 根据 C++ 的在成员函数中进行非限定名称查找的规则,必须先搜索类,然后才能在命名空间中进行搜索。 “替换失败不是错误 (SFINAE)”规则不适用(在对函数模板进行重载解析时适用)。 因此,如果类中的名称没有意义,则编译器不会继续查找更好的匹配,它会直接报告一个错误。

struct MyPage : Page
{
    void DoWork()
    {
        // This doesn't compile. You get the error
        // "'winrt::Windows::Foundation::IUnknown::as':
        // no matching overloaded function found".
        auto style{ Application::Current().Resources().
            Lookup(L"MyStyle").as<Style>() };
    }
}

在上面的代码中,编译器认为你是在将 FrameworkElement.Style()(这在 C++/WinRT 中是成员函数)作为模板参数传递给 IUnknown::as。 解决方案是将名称 Style 强制解释为类型 Windows::UI::Xaml::Style。

struct MyPage : Page
{
    void DoWork()
    {
        // One option is to fully-qualify it.
        auto style{ Application::Current().Resources().
            Lookup(L"MyStyle").as<Windows::UI::Xaml::Style>() };

        // Another is to force it to be interpreted as a struct name.
        auto style{ Application::Current().Resources().
            Lookup(L"MyStyle").as<struct Style>() };

        // If you have "using namespace Windows::UI;", then this is sufficient.
        auto style{ Application::Current().Resources().
            Lookup(L"MyStyle").as<Xaml::Style>() };

        // Or you can force it to be resolved in the global namespace (into which
        // you imported the Windows::UI::Xaml namespace when you did
        // "using namespace Windows::UI::Xaml;".
        auto style = Application::Current().Resources().
            Lookup(L"MyStyle").as<::Style>();
    }
}

非限定名称查找有一个特殊的例外,即,名称后面跟有 ::,在这种情况下,它会忽略函数、变量和枚举值。 这样你就可以执行如下所示的代码。

struct MyPage : Page
{
    void DoSomething()
    {
        Visibility(Visibility::Collapsed); // No ambiguity here (special exception).
    }
}

对 Visibility() 的调用会解析为 UIElement.Visibility 成员函数名称。 但是参数 Visibility::Collapsed 在 Visibility 一词后面跟有 ::,因此系统会忽略方法名称,编译器会查找枚举类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/327288.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

报名活动怎么做_小程序创建线上报名活动最详细攻略

报名活动怎么做&#xff1a;一篇让你掌握活动策划与营销的秘籍 在当今社会&#xff0c;无论是线上还是线下&#xff0c;活动已经成为企业营销和品牌推广的重要手段。但是&#xff0c;如何策划一场成功的活动呢&#xff1f;这篇文章将为你揭示活动策划与营销的秘籍&#xff0c;…

Python代码调试的几种方法总结

使用 pdb 进行调试 pdb 是 python 自带的一个包&#xff0c;为 python 程序提供了一种交互的源代码调试功能&#xff0c;主要特性包括设置断点、单步调试、进入函数调试、查看当前代码、查看栈片段、动态改变变量的值等。pdb 提供了一些常用的调试命令&#xff0c;详情见表 1。…

Visual Studio调试模式下无法使用右键菜单将ppt转换到pdf

Visual Studio调试模式下无法使用右键菜单将ppt转换到pdf 症状 Visual Studio调试模式下&#xff0c;程序停在断点时&#xff0c;我临时需要将ppt转为pdf&#xff0c;遂右键单击文件&#xff0c;想直接转pdf&#xff0c;奈何光标转了几秒钟&#xff0c;毫无反应。 解决方法 …

Java生成四位数随机验证码

引言&#xff1a; 我们生活中登录的时候都要输入验证码&#xff0c;这些验证码是为了增加注册或者登录难度&#xff0c;减少被人用脚本疯狂登录注册导致的一系列危害&#xff0c;减少数据库的一些压力。 毕竟那些用脚本生成的账号都是垃圾账号 本次实践&#xff1a;生成这样的…

Java基础知识整理,注释、关键字、运算符

写在开头 万丈高楼平地起&#xff0c;要想学好汉语首先学拼音&#xff0c;想学好英语首先学26个字母&#xff0c;对于编程语言来说&#xff0c;一样的道理&#xff0c;要想学好必须先掌握其基础语法和知识&#xff0c;今天我们就来唠一唠Java语言中那些出现频率极高&#xff0…

JVM基础(4)——JVM存活判定算法

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 学习必须往深处挖&…

QT quick基础:加载资源文件(字体)

一、加载字体 1、准备字体库 Roboto-Regular.ttf 2、在工程下面新建文件夹fonts&#xff0c;并将字体库放到该文件夹下面。 3、在QT Create 工程中添加字体。 添加现有文件选择Roboto-Regular.ttf。 4、执行qmake 5、在.qml文件加载字体 /* 加载字体 */FontLoader {id: f…

Unity3D学习之数据持久化——PlayerPrefs

文章目录 1. 概念2. 存储2.1 存到内存当中2.2 存到硬盘当中2.3 局限性2.4 相同键会覆盖 3.读取3.1 int型3.2 float型3.3 string型3.4 判断数据是否存在 4. 删除数据5. 存储位置6. 反射6.1 判断一个类型的对象是否可以让另一个类型为自己分配空间6.2 通过反射获得泛型类型 7 数据…

华为设备vlan下配置MSTP,STP选举

核心代码,不同实例&#xff0c;承载不同流量&#xff0c;为每个实例设置一个根网桥达到分流的效果 stp region-config //进入stp区域的设置 region-name R1 //区域命名为R1 instance 1 vlan 10 …

06-python数据容器-list列表定义/list的10个常用操作/列表的遍历/使用列表取出偶数

01-数据容器入门 为什么学习数据容器&#xff1f; 数据容器的5个分类 02-数据容器&#xff08;list列表&#xff09;列表的定义 列表的定义 列表的定义方式 嵌套列表的定义 my_list是一个列表&#xff0c;其中有两个元素&#xff0c;每一个元素又是一个列表&#xff0c;这就是…

VMware Vsphere 日志:用户 dcui@127.0.01已以vMware-client/6.5.0 的身份登录

一、事件截图&#xff1a; 二、解决办法 原因&#xff1a; 三、解决办法 1.开启锁定模式 2.操作 1、从清单中选择您的 ESXi 主机&#xff0c;然后转至管理 > 设置 > 安全配置文件&#xff0c;然后单击锁定模式的编辑按钮 2、在打开的锁定模式窗口中&#xff0c;选中启…

C++I/O流——(3)文件输入/输出(第一节)

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 含泪播种的人一定能含笑收获&#xff…

代码随想录 Leetcode18. 四数之和

题目&#xff1a; 代码&#xff08;首刷看解析 2024年1月15日&#xff09;&#xff1a; class Solution { public:vector<vector<int>> fourSum(vector<int>& nums, int target) {vector<vector<int>> result;sort(nums.begin(), nums.end(…

JVM实战(17)——模拟对象晋升

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 学习必须往深处挖&…

数据结构学习 leetcode31 下一个排列

关键词&#xff1a;下一个排列 字典序 排列 这是我在做jz38字符串的排序的时候&#xff0c;一种解题方法是字典序&#xff0c;用到的就是这种方法。这种方法支持不重复地输出全排列。 题目&#xff1a;下一个排列 思路&#xff1a; 我看了官方题解和这位大哥的题解&#xff…

dns 域名解析协议

1.1 dns 的概念 作为将域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使人更方便地访问互联网,基于C/S架构&#xff0c; 服务器端&#xff1a;53/udp, 53/tcp实际上&#xff0c;每一台 DNS 服务器都只负责管理一个有限范围&#xff08;一个或几个域&#xff09;内的主…

Vscode 上安装 Compilot

GitHub Copilot 是由 OpenAI 和 GitHub 开发的 AI 工具。其目的是通过自动完成代码来帮助开发人员使用集成开发环境 &#xff08;IDE&#xff09;&#xff0c;如 Visual Studio Code。它目前仅作为技术预览版提供&#xff0c;因此只有已在候补名单上被接受的用户才能访问它。对…

【软件工程】《软件工程》期末复习提纲

《软件工程》期末复习提纲 第一章 第二章 第三章 第四章 第五章 第六章 第七章 第八章 第九章 第十章 第十一章 第十二章 第十三章 第十四章 小题参考 大题参考 《软件工程》期末复习提纲 第一章 1.在下列选项中&#xff0c;&#xff08; &#xff09;不是软…

C#,入门教程(66)——枚举Enum的高等用法

前言&#xff1a;国内码农与国外优秀程序员的最大区别是&#xff0c;我们的专家、教授喜欢唾沫横飞地&#xff0c;夸夸其谈语言特性、框架、性能&#xff0c;唯一目的是带私货&#xff08;书籍或教程&#xff09;&#xff0c;很少能写出真有用的程序。差距在哪呢&#xff1f;基…

01章【JAVA开发入门】

计算机基本概念 计算机组成原理 计算机组装 计算机&#xff1a;电子计算机&#xff0c;俗称电脑。是一种能够按照程序运行&#xff0c;自动、高速处理海量数据的现代化智能电子设备。由硬件和软件所组成&#xff0c;没有安装任何软件的计算机称为裸机。常见的形式有台式计算机、…