windows C++-统一构造和直接实现的方法(下)

选择加入统一构造和直接实现访问(下)

在我们的示例中,MyClass.h 可能如下所示(不管是否使用 -opt[imize])。

// MyClass.h
#pragma once
#include "MyClass.g.h"
 
namespace winrt::MyProject::implementation
{
    struct MyClass : ClassT<MyClass>
    {
        MyClass() = default;
 
        static void StaticMethod();
        void Method();
    };
}
namespace winrt::MyProject::factory_implementation
{
    struct MyClass : ClassT<MyClass, implementation::MyClass>
    {
    };
}

 MyClass.cpp 是整合这一切的地方。

#include "pch.h"
#include "MyClass.h"
#include "MyClass.g.cpp" // !!It's important that you add this line!!
 
namespace winrt::MyProject::implementation
{
    void MyClass::StaticMethod()
    {
    }
 
    void MyClass::Method()
    {
    }
}

 因此,若要在现有项目中使用统一构造,需编辑每个实现的 .cpp 文件,以便在包括(和定义)实现类后 #include <Sub/Namespace/Type.g.cpp>。 该文件提供具现未定义的函数的定义。 下面是 MyClass.g.cpp 文件中的这些定义。

namespace winrt::MyProject
{
    MyClass::MyClass() :
        MyClass(make<MyProject::implementation::MyClass>())
    {
    }
    void MyClass::StaticMethod()
    {
        return MyProject::implementation::MyClass::StaticMethod();
    }
}

这样就可以高效地直接调用实现,避免调用工厂缓存,并且满足了链接器的要求,很好地完成了具现。

最后,-opt[imize] 会更改项目的 module.g.cpp(此文件用于实现 DLL 的 DllGetActivationFactory 和 DllCanUnloadNow 导出)的实现,通过消除 C++/WinRT 1.0 所需要的强类型耦合,大大加快了增量生成的速度。 这通常称为“类型擦除工厂”。 在没有 -opt[imize] 的情况下,为组件生成的 module.g.cpp 文件一开始就会包括所有实现类的定义,在本例中为 MyClass.h。 然后,它会直接创建每个类的实现工厂,如下所示。

if (requal(name, L"MyProject.MyClass"))
{
    return winrt::detach_abi(winrt::make<winrt::MyProject::factory_implementation::MyClass>());
}

同样,你不需要遵循所有细节。 需要注意的是,这需要为组件所实现的任何以及所有类进行完整的定义。 这可能会对内循环产生巨大影响,因为对单个实现的任何更改都会导致 module.g.cpp 重新编译。 在使用 -opt[imize] 的情况下,这不再是一个问题, 但所生成的 module.g.cpp 文件会出现两种情况。 第一种情况是,它不再包括任何实现类。 在此示例中,它根本不包括 MyClass.h, 而只是创建实现工厂,不需要对其实现有任何的了解。

void* winrt_make_MyProject_MyClass();
 
if (requal(name, L"MyProject.MyClass"))
{
    return winrt_make_MyProject_MyClass();
}

很明显,不需要包括其定义,只需由链接器解析 winrt_make_Component_Class 函数的定义即可。 当然,你不需考虑这一点,因为为你生成的 MyClass.g.cpp 文件(为了支持统一构造,你以前已包括了此文件)也定义该函数。 下面是为此示例生成的 MyClass.g.cpp 文件的完整内容:

void* winrt_make_MyProject_MyClass()
{
    return winrt::detach_abi(winrt::make<winrt::MyProject::factory_implementation::MyClass>());
}
namespace winrt::MyProject
{
    MyClass::MyClass() :
        MyClass(make<MyProject::implementation::MyClass>())
    {
    }
    void MyClass::StaticMethod()
    {
        return MyProject::implementation::MyClass::StaticMethod();
    }
}

如你所见,winrt_make_MyProject_MyClass 函数直接创建实现的工厂。 这一切意味着,你可以随意更改任何给定实现,根本不需要重新编译 module.g.cpp。 只有在添加或删除 Windows 运行时类的时候,才会更新 module.g.cpp,此时需将其重新编译。

重写基类虚拟方法

如果基类和派生类都是应用定义类,则派生类可能出现虚拟方法问题,但虚拟方法是在祖父 Windows 运行时类中定义的。 实际上,如果从 XAML 类派生,则会出现这种情况。 本部分的其余内容是派生类中的示例的继续。

namespace winrt::MyNamespace::implementation
{
    struct BasePage : BasePageT<BasePage>
    {
        void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs const& e);
    };

    struct DerivedPage : DerivedPageT<DerivedPage>
    {
        void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs const& e);
    };
}

层次结构为 Windows::UI::Xaml::Controls::Page<- BasePage<- DerivedPage。 BasePage::OnNavigatedFrom 方法正确重写了 Page::OnNavigatedFrom,但 DerivedPage::OnNavigatedFrom 不重写 BasePage::OnNavigatedFrom。

在这里,DerivedPage 重用 BasePage 提供的 IPageOverrides vtable,这意味着它无法重写 IPageOverrides::OnNavigatedFrom 方法。 一个可能的解决方案是让 BasePage 本身充当一个模板类,将其实现完全置于标头文件中,但这会使得事情变得相当复杂,令人不可接受。

解决方法是在基类中将 OnNavigatedFrom 方法声明为显式虚拟方法。 这样,当 DerivedPage::IPageOverrides::OnNavigatedFrom 的 vtable 条目调用 BasePage::IPageOverrides::OnNavigatedFrom 时,生成器会调用 BasePage::OnNavigatedFrom,后者因其虚拟特性,最终会调用 DerivedPage::OnNavigatedFrom。

namespace winrt::MyNamespace::implementation
{
    struct BasePage : BasePageT<BasePage>
    {
        // Note the `virtual` keyword here.
        virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs const& e);
    };

    struct DerivedPage : DerivedPageT<DerivedPage>
    {
        void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs const& e);
    };
}

 这要求类层次结构的所有成员都认可 OnNavigatedFrom 方法的返回值和参数类型。 如果它们不认可,则应使用上面的版本作为虚拟方法,并将备用内容包装好。注意,IDL 不需要声明重写的方法。 有关详细信息,请参阅实现可重写的方法。

  • 23
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值