[Windows翻译]如何从C++/WinRT实现类型转换为C++/WinRT投影类型?

702 阅读2分钟

原文地址:devblogs.microsoft.com/oldnewthing…

原文作者:devblogs.microsoft.com/oldnewthing…

发布时间:2020年8月27日

使用C++/WinRT投影工作是比较简单的。所有的东西都是智能指针类型,你用通常的方式调用它们的方法,你能调用的方法只有接口定义中的方法。

为了具体化,我们假设你有这样一个类的接口定义。

namespace Sample
{
    runtimeclass Class
    {
        Class();
        void DoSomething();
    };
};

而你是这样实现的。

namespace winrt::Sample::implementation
{
    struct Class : ClassT<Class>
    {
        Class();
        void DoSomething();

        void ImplementationMethod();
        int implementation_value = 42;
    };
}

从投射方面着手,下面是你能做什么,不能做什么。

winrt::Sample::Class c;   // can construct it
c.DoSomething();          // can invoke interface method
c.ImplementationMethod(); // not allowed
c.implementation_value++; // not allowed

另一方面,使用C++/WinRT的实现是比较麻烦的,因为你现在跨越了两个世界:你有简单的投影世界,你有丑陋的实现世界。

为了方便起见,我将省略所有的winrt::命名空间限定符。

首先,我们有对象创建模式。

// Create an object from the implementation,
// returning the projection.
Sample::Class c =
    winrt::make<implementation::Class>();

// Create an object from the implementation,
// returning a com_ptr to the implementation.
com_ptr<implementation::Class> c =
    winrt::make_self<implementation::Class>();

然后我们有对象转换模式。

// Go from the implementation to the projection.
implementation::Class* p;
Sample::Class c = *p;

// Go from the implementation's com_ptr to the projection.
com_ptr<implementation::Class> ptr;
Sample::Class c = *ptr;

实现类包含了到它的投影运行时类的转换,以及它所有的接口。所以你只需要dereference原始指针或com_ptr,然后让转换启动。

这里有一个小窍门。你必须确保不要错误地复制对象!

implementation::Class* p;
auto o = *p; // bad idea
if (case1) {
  Sample::Class c = o;
} else {
  IInspectable i = o;
}

这段代码想把dereference操作符因式化,然后在后面进行转换,这要看是在什么情况下。问题是o要成为对象的副本,这会引起各种问题,因为对象是由其内部的引用计数管理的,复制到本地会引起各种问题。复制会得到一个引用计数的副本,而这个引用计数现在是不正确的。而且当它离开作用域时,副本会被销毁,而不管它的实际引用数是多少。幸运的是,debug 构建会通过错误的

error C2259: 'winrt::Sample::implementation::Class': cannot instantiate abstract class due to following members:
'void winrt::impl::root_implements<D,winrt::Sample::Class>::use_make_function_to_create_this_object(void)': is abstract

下一次,我们来看看更难的工作,从投影回到实施。


www.deepl.com 翻译