Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu konuda, doğrudan veya dolaylı olarak winrt::implements temel yapısını kullanarak C++/WinRT API'lerinin nasıl yazdığı gösterilmektedir. Bu bağlamda author için eş anlamlılar üretmek veya uygulamaktır. Bu konu, C++/WinRT türünde API'leri bu sırayla uygulamaya yönelik aşağıdaki senaryoları kapsar.
Note
Bu konu yalnızca C++/WinRT bağlamında Windows Çalışma Zamanı bileşenleri konusuna değinir. Tüm Windows Çalışma Zamanı dilleri kapsayan Windows Çalışma Zamanı bileşenleri hakkında içerik arıyorsanız bkz. Windows Çalışma Zamanı bileşenleri.
- Windows Çalışma Zamanı sınıfı (çalışma zamanı sınıfı) yazmıyorsanız, yalnızca uygulamanızda yerel tüketim için bir veya daha fazla Windows Çalışma Zamanı arabirimi uygulamak istiyorsunuz. Bu durumda doğrudan winrt::implements sınıfından türersiniz ve fonksiyonları gerçeklersiniz.
- Bir çalışma zamanı sınıfı oluşturuyorsunuz. Bir uygulamadan tüketilecek bir bileşen yazabilirsiniz. Ya da XAML kullanıcı arabirimi (UI) tarafından kullanılacak bir tür yazıyor olabilirsiniz; bu durumda, aynı derleme birimi içinde bir çalışma zamanı sınıfını hem uyguluyor hem de kullanıyor olursunuz. Bu durumlarda, araçların sizin için winrt::implements dosyasından türetilen sınıflar oluşturmasına izin verirsiniz.
Her iki durumda da C++/WinRT API'lerinizi uygulayan tür uygulama türü olarak adlandırılır.
Önemli
Gerçekleme türü kavramını yansıtılmış tür kavramından ayırt etmek önemlidir. Öngörülen tür, C++/WinRT ile API'leri kullanma bölümünde açıklanmıştır.
Bir çalışma zamanı sınıfı oluşturmuyorsanız
En basit senaryo, türünüzün bir Windows Çalışma Zamanı arabirimi uyguladığı ve bu türü aynı uygulama içinde tüketeceğiniz senaryodur. Bu durumda, türünüzün çalışma zamanı sınıfı olması gerekmez; sıradan bir C++ sınıfı. Örneğin, Microsoft::UI::Xaml::Application tabanlı bir WinUI 3 masaüstü uygulaması yazıyor olabilirsiniz.
Türünüz XAML kullanıcı arabirimi tarafından başvurulursa, XAML ile aynı projede olsa bile bir çalışma zamanı sınıfı olması gerekir. Bu durumda, XAML kullanıcı arabiriminizde başvurulacak bir çalışma zamanı sınıfı yazıyorsanız bölümüne bakın.
Note
C++/WinRT Visual Studio Uzantısını (VSIX) ve NuGet paketini (birlikte proje şablonu ve derleme desteği sağlayan) yükleme ve kullanma hakkında bilgi için bkz. C++/WinRT için Visual Studio desteği.
Visual Studio'de, C++ için Paketlenmiş (Masaüstünde WinUI 3) Boş Uygulama proje şablonu WinUI 3 uygulama desenini gösterir. Uygulama sınıfı Microsoft::UI::Xaml::Application'dan türetilir ve giriş noktası Start yöntemini çağırır.
#include "App.xaml.h"
int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
winrt::init_apartment();
::winrt::Microsoft::UI::Xaml::Application::Start(
[](auto&&) { ::winrt::make<App>(); });
}
Uygulama sınıfı bir Microsoft::UI::Xaml::Window oluşturur ve OnLaunched içinde etkinleştirir.
// App.xaml.h
struct App : AppT<App>
{
App();
void OnLaunched(Microsoft::UI::Xaml::LaunchActivatedEventArgs const&);
private:
winrt::Microsoft::UI::Xaml::Window window{ nullptr };
};
// App.xaml.cpp
void App::OnLaunched(LaunchActivatedEventArgs const&)
{
window = make<MainWindow>();
window.Activate();
}
C++/WinRT, COM stili programlamaya başvurmadan bir arabirim (veya birkaç) uygulamayı kolaylaştırmak için winrt::implements temel yapı şablonuna sahiptir. Yalnızca türünüzü implements temel alarak türetirsiniz, ardından da arabirimin işlevlerini uygularsınız. Burada özel arabirim uygulayan bir örnek verilmiştir.
struct MyType : implements<MyType, IStringable>
{
hstring ToString()
{
return L"MyType";
}
};
Bir Windows Çalışma Zamanı bileşeninde çalışma zamanı sınıfı oluşturuyorsanız
Türünüz, başka bir ikili tarafından kullanılmak üzere bir Windows Çalışma Zamanı bileşeninde paketlenmişse (diğer ikili genellikle bir uygulamadır), türünüzün bir çalışma zamanı sınıfı olması gerekir. bir Microsoft Arabirim Tanım Dili (IDL) (.idl) dosyasında bir çalışma zamanı sınıfı bildirirsiniz (bkz. Çalışma zamanı sınıflarını Midl dosyalarına (.idl) aktarma).
Her IDL dosyası bir .winmd dosyaya neden olur ve Visual Studio bunların tümünü kök ad alanınızla aynı ada sahip tek bir dosyada birleştirir. Bu son .winmd dosya, bileşeninizin tüketicilerinin başvuracağı dosya olacaktır.
IdL dosyasında çalışma zamanı sınıfı bildirme örneği aşağıda verilmiştir.
// MyRuntimeClass.idl
namespace MyProject
{
runtimeclass MyRuntimeClass
{
// Declaring a constructor (or constructors) in the IDL causes the runtime class to be
// activatable from outside the compilation unit.
MyRuntimeClass();
String Name;
}
}
Bu IDL bir Windows Çalışma Zamanı (çalışma zamanı) sınıfı bildirir. Çalışma zamanı sınıfı, genellikle yürütülebilir sınırlar boyunca modern COM arabirimleri aracılığıyla etkinleştirilebilen ve kullanılabilen bir türdür. Projenize bir IDL dosyası ekleyip derleme yaptığınızda, C++/WinRT araç zinciri (midl.exe ve cppwinrt.exe) sizin için bir uygulama türü oluşturur. IdL dosya iş akışının bir örneği için bkz. XAML denetimleri; C++/WinRT özelliğine bağlama.
Yukarıdaki örnek IDL kullanıldığında, uygulama türü, adı \MyProject\MyProject\Generated Files\sources\MyRuntimeClass.h ve MyRuntimeClass.cpp olan kaynak kodu dosyalarında bulunan winrt::MyProject::implementation::MyRuntimeClass adlı bir C++ struct saplamasıdır.
Uygulama türü şöyle görünür.
// MyRuntimeClass.h
...
namespace winrt::MyProject::implementation
{
struct MyRuntimeClass : MyRuntimeClassT<MyRuntimeClass>
{
MyRuntimeClass() = default;
winrt::hstring Name();
void Name(winrt::hstring const& value);
};
}
// winrt::MyProject::factory_implementation::MyRuntimeClass is here, too.
Kullanılan F-bağlı polimorfizm desenine dikkat edin (MyRuntimeClass, taban sınıfı MyRuntimeClassT için şablon argümanı olarak kendisini kullanır). Bu, merakla yinelenen şablon deseni (CRTP) olarak da adlandırılır. Devralma zincirini yukarı doğru izlerseniz MyRuntimeClass_base karşılaşırsınız.
Windows Uygulama Kitaplıkları (WIL) kullanarak basit özelliklerin uygulanmasını basitleştirebilirsiniz. Şunu yapabilirsiniz:
// MyRuntimeClass.h
...
namespace winrt::MyProject::implementation
{
struct MyRuntimeClass : MyRuntimeClassT<MyRuntimeClass>
{
MyRuntimeClass() = default;
wil::single_threaded_rw_property<winrt::hstring> Name;
};
}
Bkz . Basit özellikler.
template <typename D, typename... I>
struct MyRuntimeClass_base : implements<D, MyProject::IMyRuntimeClass, I...>
Bu nedenle, bu senaryoda devralma hiyerarşisinin kökünde winrt::implements temel yapı şablonu bir kez daha bulunur.
Daha fazla ayrıntı, kod örnekleri ve bir Windows Çalışma Zamanı bileşeninde API’ler oluşturma hakkında adım adım açıklama için bkz. C++/WinRT ile Windows Çalışma Zamanı bileşenleri ve C++/WinRT’de olaylar oluşturma.
XAML kullanıcı arabiriminizde başvurulan bir çalışma zamanı sınıfı oluşturuyorsanız
XAML kullanıcı arayüzünüz türünüze başvuruyorsa, XAML ile aynı projede yer alsa bile bunun bir çalışma zamanı sınıfı olması gerekir. Bunlar genellikle yürütülebilir sınırlar arasında etkinleştirilse de, çalışma zamanı sınıfı bunun yerine bunu uygulayan derleme birimi içinde kullanılabilir.
Bu senaryoda API'leri hem geliştiriyor hem de kullanıyorsunuz. Çalışma zamanı sınıfınızı uygulama yordamı temelde bir Windows Çalışma Zamanı bileşeniyle aynıdır. Bu nedenle, bir Windows Çalışma Zamanı bileşeninde çalışma zamanı sınıfı yazıyorsanız önceki bölüme bakın. Farklı olan tek ayrıntı, IDL'den C++/WinRT araç zincirinin yalnızca bir uygulama türü değil, aynı zamanda öngörülen bir tür oluşturmasıdır. Bu senaryoda yalnızca "MyRuntimeClass" demenin belirsiz olabileceğinin farkında olmak önemlidir; çünkü farklı türlerden bu adı taşıyan birkaç varlık vardır.
- MyRuntimeClass , çalışma zamanı sınıfının adıdır. Ancak bu gerçekten bir soyutlamadır: IDL'de bildirilir ve bazı programlama dillerinde uygulanır.
-
MyRuntimeClass , çalışma zamanı sınıfının C++/WinRT uygulaması olan C++ yapısı winrt::MyProject::implementation::MyRuntimeClass'ın adıdır. Gördüğümüz gibi, ayrı uygulama ve kullanma projeleri varsa, bu yapı yalnızca uygulama projesinde bulunur. Bu , uygulama türü veya uygulamadır. Bu tür,
cppwinrt.exearacı tarafından\MyProject\MyProject\Generated Files\sources\MyRuntimeClass.hveMyRuntimeClass.cppdosyalarında oluşturulur. -
MyRuntimeClass , C++ yapısı winrt::MyProject::MyRuntimeClass biçiminde öngörülen türün adıdır. Ayrı uygulayan ve tüketen projeler varsa, bu yapı yalnızca tüketen projede bulunur. Bu, öngörülen tür veya projeksiyondur. Bu tür,
\MyProject\MyProject\Generated Files\winrt\impl\MyProject.2.hdosyasında (cppwinrt.exetarafından) oluşturulur.
Bu konu başlığıyla ilgili olarak, öngörülen türün bölümleri aşağıdadır.
// MyProject.2.h
...
namespace winrt::MyProject
{
struct MyRuntimeClass : MyProject::IMyRuntimeClass
{
MyRuntimeClass(std::nullptr_t) noexcept {}
MyRuntimeClass();
};
}
Bir çalışma zamanı sınıfında INotifyPropertyChanged arabirimini uygulamanın örnek bir kılavuzu için bkz. XAML denetimleri; C++/WinRT özelliğine bağlama.
Bu senaryoda çalışma zamanı sınıfınızı kullanma yordamı , C++/WinRT ile API'leri kullanma başlığında açıklanmıştır.
Çalışma zamanı sınıflarını Midl dosyalarına (.idl) aktarma
Visual Studio proje ve öğe şablonları her çalışma zamanı sınıfı için ayrı bir IDL dosyası oluşturur. Bu, bir IDL dosyası ile oluşturulan kaynak kod dosyaları arasında mantıksal bir yazışma sağlar.
Ancak, projenizin tüm çalışma zamanı sınıflarını tek bir IDL dosyasında birleştirirseniz bu, derleme süresini önemli ölçüde iyileştirebilir. Eğer bunlar arasında aksi takdirde karmaşık (veya döngüsel) import bağımlılıklar oluşacaksa, bunları tek bir yerde toplamak gerçekten gerekli olabilir. Ayrıca, çalışma zamanı sınıflarınız bir arada olduğunda, bunları oluşturmak ve gözden geçirmek daha kolay olabilir.
Çalışma zamanı sınıf oluşturucuları
Yukarıda gördüğümüz listelerden çıkaracağımız bazı noktalar aşağıdadır.
- IDL'nizde bildirdiğiniz her oluşturucu, hem uygulama türünüzde hem de yansıtılan türünüzde bir oluşturucu oluşturulmasına neden olur. IDL tarafından bildirilen oluşturucular, çalışma zamanı sınıfını farklı bir derleme biriminden kullanmak için kullanılır.
- IDL tarafından bildirilen oluşturucularınız olsun veya olmasın, öngörülen türünüzde std::nullptr_t alan bir oluşturucu aşırı yüklemesi oluşturulur. std::nullptr_t oluşturucusunun çağrılması, çalışma zamanı sınıfını aynı derleme biriminden kullanma işlemindekiiki adımın ilkidir. Daha fazla ayrıntı ve kod örneği için bkz . C++/WinRT ile API'leri kullanma.
- Çalışma zamanı sınıfını aynı derleme biriminden kullanıyorsanız, varsayılan olmayan kurucuları doğrudan uygulama türü üzerinde de tanımlayabilirsiniz (ki, hatırlarsanız, bu tür
MyRuntimeClass.hiçindedir).
Note
Çalışma zamanı sınıfınızın farklı bir derleme biriminden kullanılmasını bekliyorsanız (ki bu yaygın bir durumdur), IDL'nize yapıcıları (en azından varsayılan bir yapıcıyı) ekleyin. Bunu yaparak, uygulama türünüzle birlikte bir fabrika uygulaması da alırsınız.
Çalışma zamanı sınıfınızı yalnızca aynı derleme birimi içinde yazmak ve kullanmak istiyorsanız, IDL'nizde herhangi bir oluşturucu bildirmeyin. Bir fabrika uygulamasına ihtiyacınız yoktur ve bir tane oluşturulmaz. Uygulama türünüzün varsayılan oluşturucuları silinir, ancak bunun yerine kolayca düzenleyebilir ve varsayılan olarak ayarlayabilirsiniz.
Çalışma zamanı sınıfınızı yalnızca aynı derleme birimi içinde yazmak ve kullanmak istiyorsanız ve oluşturucu parametrelerine ihtiyacınız varsa, doğrudan uygulama türünüzde ihtiyacınız olan oluşturucuları yazın.
Çalışma zamanı sınıfı yöntemleri, özellikleri ve olayları
İş akışında çalışma zamanı sınıfınızı ve üyelerini tanımlamak için IDL kullanıldığını, ardından araçların sizin için prototipler ve stub uygulamaları oluşturduğunu gördük. Çalışma zamanı sınıfınızın üyeleri için otomatik olarak oluşturulan prototiplere gelince, bunları IDL’nizde bildirdiğiniz türlerden farklı türleri kullanacak şekilde düzenleyebilirsiniz. Ancak bunu yalnızca IDL'de tanımladığınız tür, uygulamadaki sürümde tanımladığınız türe yönlendirilebildiği sürece yapabilirsiniz.
Aşağıda bazı örnekler verilmiştir.
- Parametre türlerini gevşetebilirsiniz. Örneğin, IDL'de yönteminiz bir SomeClass alıyorsa, bunu uygulamanızda IInspectable olarak değiştirmeyi seçebilirsiniz. Bu işe yarar çünkü herhangi bir SomeClassIInspectable'a iletilebilir (tersi elbette işe yaramaz).
- Bir kopyalanabilir parametreyi başvuru yerine değere göre kabul edebilirsiniz. Örneğin,
SomeClass const&'iSomeClassile değiştirin. Bu, bir referansı coroutine içine yakalamaktan kaçınmanız gerektiğinde gereklidir (bkz. Parametre geçirme). - Dönüş değerini esnetebilirsiniz. Örneğin, void değerini winrt::fire_and_forget olarak değiştirebilirsiniz.
Son ikisi, zaman uyumsuz bir olay işleyicisi yazarken çok yararlıdır.
Uygulama türlerini ve arabirimlerini örnekleme ve döndürme
Bu bölümde, IStringable ve IClosable arabirimlerini uygulayan MyType adlı bir uygulama türünü örnek olarak ele alalım.
MyType'ı doğrudan winrt::implements öğesinden türetebilirsiniz (çalışma zamanı sınıfı değildir).
#include <winrt/Windows.Foundation.h>
using namespace winrt;
using namespace Windows::Foundation;
struct MyType : implements<MyType, IStringable, IClosable>
{
winrt::hstring ToString(){ ... }
void Close(){}
};
Veya IDL'den oluşturabilirsiniz (bu bir çalışma zamanı sınıfıdır).
// MyType.idl
namespace MyProject
{
runtimeclass MyType: Windows.Foundation.IStringable, Windows.Foundation.IClosable
{
MyType();
}
}
Uygulama türünüzü doğrudan ayıramazsınız.
MyType myimpl; // error C2259: 'MyType': cannot instantiate abstract class
Ancak, winrt::make işlev şablonunu çağırarak MyType'dan, projeksiyonunuzun bir parçası olarak kullanabileceğiniz veya döndürebileceğiniz bir IStringable ya da IClosable nesnesi elde edebilirsiniz. make , uygulama türünün varsayılan arabirimini döndürür.
IStringable istringable = winrt::make<MyType>();
Note
Ancak, XAML kullanıcı arabiriminizden türünüzü başvuruyorsanız, aynı projede hem uygulama türü hem de öngörülen tür olacaktır. Bu durumda, make yansıtılan türün bir örneğini döndürür. Bu senaryonun kod örneği için bkz . XAML denetimleri; C++/WinRT özelliğine bağlama.
Yalnızca istringable arabiriminin üyelerini çağırmak için kullanabiliriz (yukarıdaki kod örneğinde). Ancak C++/WinRT arabirimi (yansıtılan arabirim) winrt::Windows::Foundation::IUnknown'dan türetilir. Bu nedenle, diğer yansıtılan türleri veya arabirimleri sorgulamak için üzerinde IUnknown: ::as (veya IUnknown::try_as) çağrısı yapabilirsiniz; bunu kullanabilir veya döndürebilirsiniz.
Tavsiye
çağırmamanız gerekenas veya try_as için bir senaryo, çalışma zamanı sınıf türetmedir ("birleştirilebilir sınıflar"). Bir uygulama türü başka bir sınıfı bileştiriyorsa, bileştirilen sınıf üzerinde denetlenmemiş veya denetlenmiş bir QueryInterface gerçekleştirmek için as ya da try_as çağırmayın. Bunun yerine, (this->) m_inner veri üyesine erişin ve bu üye üzerinde as veya try_as çağırın. Daha fazla bilgi için bu konudaki Çalışma zamanı sınıfı türetme bölümüne bakın.
istringable.ToString();
IClosable iclosable = istringable.as<IClosable>();
iclosable.Close();
Uygulamanın tüm üyelerine erişmeniz ve daha sonra çağırana bir arabirim döndürmeniz gerekiyorsa winrt::make_self işlev şablonunu kullanın. make_self, uygulama türünü saran bir winrt::com_ptr döndürür. Tüm arabirimlerinin üyelerine erişebilirsiniz (ok işlecini kullanarak), onu olduğu gibi çağırana geri döndürebilir veya üzerinde as çağrısı yapıp elde edilen arabirim nesnesini çağırana geri döndürebilirsiniz.
winrt::com_ptr<MyType> myimpl = winrt::make_self<MyType>();
myimpl->ToString();
myimpl->Close();
IClosable iclosable = myimpl.as<IClosable>();
iclosable.Close();
MyType sınıfı yansıtmanın bir parçası değildir; uygulamadır. Ancak bu şekilde, sanal işlev çağrısının yükü olmadan uygulama yöntemlerini doğrudan çağırabilirsiniz. Yukarıdaki örnekte MyType::ToString , IStringable'da yansıtılan yöntemle aynı imzayı kullansa da, uygulama ikili arabirimini (ABI) aşmadan sanal olmayan yöntemi doğrudan çağırıyoruz.
com_ptr, MyType yapısına yönelik bir işaretçi tutar, böylece myType'ın diğer iç ayrıntılarına değişkeni ve ok işleci aracılığıyla da erişebilirsiniz.myimpl
Bir arabirim nesnenizin olması ve bunun uygulamanızda bir arabirim olduğunu biliyor olmanız durumunda , winrt::get_self işlev şablonunu kullanarak uygulamaya geri dönebilirsiniz. Bu, sanal işlev çağrılarını önleyen ve doğrudan uygulamaya geçmenizi sağlayan bir tekniktir.
Note
Windows SDK sürüm 10.0.17763.0 (Windows 10, sürüm 1809) veya sonraki bir sürümü yüklemediyseniz winrt::get_self yerine winrt::from_abi çağrısı yapmanız gerekir.
İşte bir örnek. BgLabelControl özel denetim sınıfını uygulama bölümünde başka bir örnek vardır.
void ImplFromIClosable(IClosable const& from)
{
MyType* myimpl = winrt::get_self<MyType>(from);
myimpl->ToString();
myimpl->Close();
}
Ancak yalnızca orijinal arabirim nesnesi bir referansı elinde tutar. Eğer bunu saklamak istiyorsanız, o zaman com_ptr::copy_from işlevini çağırabilirsiniz.
winrt::com_ptr<MyType> impl;
impl.copy_from(winrt::get_self<MyType>(from));
// com_ptr::copy_from ensures that AddRef is called.
Uygulama türünün kendisi winrt::Windows::Foundation::IUnknown'dan türetilmez, bu nedenle işlevi yoktur. Yine de, yukarıdaki ImplFromIClosable işlevinde görebileceğiniz gibi, tüm arabirimlerinin üyelerine erişebilirsiniz. Ancak bunu yaparsanız ham uygulama türü örneğini çağırana döndürmeyin. Bunun yerine, zaten gösterilmiş tekniklerden birini kullanın ve projeksiyonu yapılmış bir arabirim ya da bir com_ptr döndürün.
Uygulama türünüzün bir örneğine sahipseniz ve bunu ilgili öngörülen türü bekleyen bir işleve geçirmeniz gerekiyorsa, bunu aşağıdaki kod örneğinde gösterildiği gibi yapabilirsiniz. Bunu mümkün kılan uygulama türünüzde (uygulama türünün araç tarafından oluşturulması koşuluyla cppwinrt.exe ) bir dönüştürme işleci vardır. Uygulama türündeki bir değeri, karşılık gelen yansıtılmış türde bir değer bekleyen bir yönteme doğrudan parametre olarak verebilirsiniz. Uygulama türünün bir üye işlevinden, *this değerini karşılık gelen yansıtılan türün değerini bekleyen bir yönteme geçirebilirsiniz.
// MyClass.idl
import "MyOtherClass.idl";
namespace MyProject
{
runtimeclass MyClass
{
MyClass();
void MemberFunction(MyOtherClass oc);
}
}
// MyClass.h
...
namespace winrt::MyProject::implementation
{
struct MyClass : MyClassT<MyClass>
{
MyClass() = default;
void MemberFunction(MyProject::MyOtherClass const& oc) { oc.DoWork(*this); }
};
}
...
// MyOtherClass.idl
import "MyClass.idl";
namespace MyProject
{
runtimeclass MyOtherClass
{
MyOtherClass();
void DoWork(MyClass c);
}
}
// MyOtherClass.h
...
namespace winrt::MyProject::implementation
{
struct MyOtherClass : MyOtherClassT<MyOtherClass>
{
MyOtherClass() = default;
void DoWork(MyProject::MyClass const& c){ /* ... */ }
};
}
...
//main.cpp
#include "pch.h"
#include <winrt/base.h>
#include "MyClass.h"
#include "MyOtherClass.h"
using namespace winrt;
// MyProject::MyClass is the projected type; the implementation type would be MyProject::implementation::MyClass.
void FreeFunction(MyProject::MyOtherClass const& oc)
{
auto defaultInterface = winrt::make<MyProject::implementation::MyClass>();
MyProject::implementation::MyClass* myimpl = winrt::get_self<MyProject::implementation::MyClass>(defaultInterface);
oc.DoWork(*myimpl);
}
...
Çalışma zamanı sınıfı türetme
Temel sınıfın "korumasız" olarak bildirilmiş olması koşuluyla, başka bir çalışma zamanı sınıfından türetilen bir çalışma zamanı sınıfı oluşturabilirsiniz. Sınıf türetme için Windows Çalışma Zamanı terim "birleştirilebilir sınıflar"dır. Türetilmiş bir sınıf uygulama kodu, temel sınıfın başka bir bileşen tarafından mı yoksa aynı bileşen tarafından mı sağlandığına bağlıdır. Neyse ki bu kuralları öğrenmek zorunda değilsiniz; yalnızca cppwinrt.exe derleyicisinin ürettiği sources çıkış klasöründeki örnek gerçekleştirimleri kopyalayabilirsiniz.
Bu örneği göz önünde bulundurun.
// MyProject.idl
namespace MyProject
{
[default_interface]
runtimeclass MyButton : Microsoft.UI.Xaml.Controls.Button
{
MyButton();
}
unsealed runtimeclass MyBase
{
MyBase();
overridable Int32 MethodOverride();
}
[default_interface]
runtimeclass MyDerived : MyBase
{
MyDerived();
}
}
Yukarıdaki örnekte MyButton , başka bir bileşen tarafından sağlanan XAML Düğmesi denetiminden türetilmiştir. Bu durumda, uygulama aynı birleştirilebilir olmayan sınıfın uygulanması gibi görünür:
namespace winrt::MyProject::implementation
{
struct MyButton : MyButtonT<MyButton>
{
};
}
namespace winrt::MyProject::factory_implementation
{
struct MyButton : MyButtonT<MyButton, implementation::MyButton>
{
};
}
Öte yandan, yukarıdaki örnekte MyDerived aynı bileşendeki başka bir sınıftan türetilmiştir. Bu durumda, uygulama için temel sınıf için uygulama sınıfını belirten ek bir şablon parametresi gerekir.
namespace winrt::MyProject::implementation
{
struct MyDerived : MyDerivedT<MyDerived, implementation::MyBase>
{ // ^^^^^^^^^^^^^^^^^^^^^^
};
}
namespace winrt::MyProject::factory_implementation
{
struct MyDerived : MyDerivedT<MyDerived, implementation::MyDerived>
{
};
}
Her iki durumda da uygulamanız, temel sınıftaki bir yöntemi base_type tür diğer adını kullanarak çağırabilir:
namespace winrt::MyProject::implementation
{
struct MyButton : MyButtonT<MyButton>
{
void OnApplyTemplate()
{
// Call base class method
base_type::OnApplyTemplate();
// Do more work after the base class method is done
DoAdditionalWork();
}
};
struct MyDerived : MyDerivedT<MyDerived, implementation::MyBase>
{
int MethodOverride()
{
// Return double what the base class returns
return 2 * base_type::MethodOverride();
}
};
}
Tavsiye
Bir uygulama türü başka bir sınıfı bileştiriyorsa, bileştirilen sınıf üzerinde denetlenmemiş veya denetlenmiş bir QueryInterface gerçekleştirmek için as ya da try_as çağırmayın. Bunun yerine, (this->) m_inner veri üyesine erişin ve bu üye üzerinde as veya try_as çağırın.
Varsayılan olmayan bir oluşturucuya sahip bir türden türetme
ToggleButtonAutomationPeer::ToggleButtonAutomationPeer(ToggleButton), varsayılan olmayan bir oluşturucu örneğidir. Varsayılan bir oluşturucu olmadığından, bir ToggleButtonAutomationPeer oluşturmak için bir owner nesnesi geçirmeniz gerekir. Sonuç olarak, ToggleButtonAutomationPeer sınıfından türetiyorsanız, owner alan ve bunu temel sınıfa geçiren bir oluşturucu tanımlamanız gerekir. Şimdi bunun pratikte nasıl göründüğüne bakalım.
// MySpecializedToggleButton.idl
namespace MyNamespace
{
runtimeclass MySpecializedToggleButton :
Microsoft.UI.Xaml.Controls.Primitives.ToggleButton
{
...
};
}
// MySpecializedToggleButtonAutomationPeer.idl
namespace MyNamespace
{
runtimeclass MySpecializedToggleButtonAutomationPeer :
Microsoft.UI.Xaml.Automation.Peers.ToggleButtonAutomationPeer
{
MySpecializedToggleButtonAutomationPeer(MySpecializedToggleButton owner);
};
}
Uygulama türünüz için oluşturulan oluşturucu şöyle görünür.
// MySpecializedToggleButtonAutomationPeer.cpp
...
MySpecializedToggleButtonAutomationPeer::MySpecializedToggleButtonAutomationPeer
(MyNamespace::MySpecializedToggleButton const& owner)
{
...
}
...
Eksik olan tek parça, bu oluşturucu parametresini temel sınıfa geçirmeniz gerektiğidir. Yukarıda bahsettiğimiz F bağlı polimorfizm desenini hatırlıyor musunuz? C++/WinRT tarafından kullanılan desenin ayrıntılarını öğrendikten sonra, temel sınıfınızın adını anlayabilirsiniz (veya uygulama sınıfınızın üst bilgi dosyasına bakabilirsiniz). Bu örnekte temel sınıf oluşturucuyu çağırma yöntemi budur.
// MySpecializedToggleButtonAutomationPeer.cpp
...
MySpecializedToggleButtonAutomationPeer::MySpecializedToggleButtonAutomationPeer
(MyNamespace::MySpecializedToggleButton const& owner) :
MySpecializedToggleButtonAutomationPeerT<MySpecializedToggleButtonAutomationPeer>(owner)
{
...
}
...
Temel sınıf oluşturucu bir ToggleButton bekler. MySpecializedToggleButtonise birToggleButton'tır.
Yukarıda açıklanan düzenlemeyi yapıncaya kadar (bu oluşturucu parametresini temel sınıfa geçirmek için), derleyici oluşturucunuza bayrak ekler ve MySpecializedToggleButtonAutomationPeer< MySpecializedToggleButtonAutomationPeer_base> adlı bir tür üzerinde uygun varsayılan oluşturucu olmadığına işaret eder. Bu aslında uygulama türünüzün bas sınıfının temel sınıfıdır.
Ad alanları: öngörülen türler, uygulama türleri ve fabrikalar
Bu konuda daha önce gördüğünüz gibi, bir C++/WinRT çalışma zamanı sınıfı, birden fazla ad alanında birden fazla C++ sınıfı olarak bulunur. Bu nedenle , MyRuntimeClass adının winrt::MyProject ad alanında bir anlamı ve winrt::MyProject::implementation ad alanında farklı bir anlamı vardır. Şu anda bağlam içinde hangi ad alanına sahip olduğunuzu unutmayın ve farklı bir ad alanından bir ad alanına ihtiyacınız varsa ad alanı ön eklerini kullanın. Şimdi söz konusu ad alanlarına daha yakından bakalım.
- winrt::MyProject. Bu ad alanı öngörülen türler içeriyor. Projeksiyonu yapılmış bir türün nesnesi bir vekildir; özünde, arka plandaki bir nesneyi işaret eden akıllı bir işaretçidir ve bu arka plandaki nesne burada, projenizde uygulanmış olabileceği gibi başka bir derleme biriminde de uygulanmış olabilir.
- winrt::MyProject::implementation. Bu ad alanı uygulama türleri içerir. Uygulama türünün nesnesi işaretçi değildir; tam bir C++ yığın nesnesi olan bir değerdir. Doğrudan uygulama türü oluşturma; bunun yerine, uygulama türünüzü şablon parametresi olarak geçirerek winrt::make öğesini çağırın. Daha önce bu konuda winrt::make in action örneklerini gösterdik ve XAML denetimlerinde başka bir örnek daha var; C++/WinRT özelliğine bağlama. Ayrıca bkz. Doğrudan tahsisleri tanılama.
- winrt::MyProject::factory_implementation. Bu ad alanı fabrikaları içerir. Bu ad alanında bir nesne IActivationFactory'yi destekler.
Bu tablo, farklı bağlamlarda kullanmanız gereken en düşük ad alanı nitelemini gösterir.
| Bağlam içindeki ad alanı | Öngörülen türü belirtmek için | Uygulama türünü belirtmek için |
|---|---|---|
| winrt::MyProject | MyRuntimeClass |
implementation::MyRuntimeClass |
| winrt::MyProject::implementation | MyProject::MyRuntimeClass |
MyRuntimeClass |
Önemli
Uygulamanızdan yansıtılmış bir tür döndürmek istediğinizde, MyRuntimeClass myRuntimeClass; yazarak uygulama türünün bir örneğini oluşturmamaya dikkat edin. Bu senaryo için doğru teknikler ve kod, bu konuda daha önce uygulama türlerini ve arabirimlerini örnekleme ve döndürme bölümünde gösterilmiştir.
Bu senaryoda sorun MyRuntimeClass myRuntimeClass; , yığında bir winrt::MyProject::implementation::MyRuntimeClass nesnesi oluşturmasıdır. Bu nesne (uygulama türünde) bazı şekillerde yansıtılan tür gibi davranır; üzerinde aynı şekilde yöntemler çağırabilirsiniz; ve hatta yansıtılan bir türe dönüştürülür. Ancak nesne, normal C++ kurallarına göre kapsam çıktığında yok olur. Dolayısıyla, o nesne için bir projeksiyon türü (akıllı işaretçi) döndürdüyseniz, bu işaretçi artık boşta kalmış demektir.
Hatanın bu bellek bozulması türünü tanılamak zordur. Bu nedenle, hata ayıklama derlemeleri için C++/WinRT onayı, yığın algılayıcısı kullanarak bu hatayı yakalamanıza yardımcı olur. Ancak eş yordamlar yığında tahsis edilir, bu nedenle bu hatayı bir eş yordam içinde yaparsanız bu konuda size yardımcı olunmaz. Daha fazla bilgi için bkz. Doğrudan ayırmaları tanılama.
Çeşitli C++/WinRT özellikleriyle öngörülen türleri ve uygulama türlerini kullanma
Aşağıda, C++/WinRT özelliklerinin bir tür beklediği çeşitli yerler ve bu yerlerde hangi türün beklendiği (öngörülen tür, uygulama türü veya her ikisi) belirtilmiştir.
| Özellik | Kabul eder | Notes |
|---|---|---|
T (akıllı işaretçiyi temsil eden) |
Öngörülen | Ad Alanları: öngörülen türler, uygulama türleri ve fabrikalar bölümünde uygulama türünü yanlışlıkla kullanma konusunda dikkatli olun. |
agile_ref<T> |
Both | Uygulama türünü kullanırsanız oluşturucu bağımsız değişkeni olmalıdır com_ptr<T>. |
com_ptr<T> |
Implementation | Öngörülen türün kullanılması şu hatayı oluşturur: 'Release' is not a member of 'T'. |
default_interface<T> |
Both | Uygulama türünü kullanırsanız, uygulanan ilk arabirim döndürülür. |
get_self<T> |
Implementation | Öngörülen türün kullanılması şu hatayı oluşturur: '_abi_TrustLevel': is not a member of 'T'. |
guid_of<T>() |
Both | Varsayılan arabirimin GUID değerini döndürür. |
IWinRTTemplateInterface<T> |
Öngörülen | Uygulama türünü kullanmak derlemeleri oluşturur, ancak bu bir hatadır. Ad alanları: öngörülen türler, uygulama türleri ve fabrikalar konusunda dikkatli olun. |
make<T> |
Implementation | Öngörülen türün kullanılması şu hatayı oluşturur: 'implements_type': is not a member of any direct or indirect base class of 'T' |
make_agile(T const&) |
Both | Uygulama türünü kullanırsanız, bağımsız değişken com_ptr<T> olmalıdır. |
make_self<T> |
Implementation | Öngörülen türün kullanılması şu hatayı oluşturur: 'Release': is not a member of any direct or indirect base class of 'T' |
name_of<T> |
Öngörülen | Uygulama türünü kullanırsanız, varsayılan arabirimin dizeli GUID'sini alırsınız. |
weak_ref<T> |
Both | Uygulama türünü kullanırsanız, oluşturucu bağımsız değişkeni com_ptr<T> olmalıdır. |
Tekdüzen inşaatı kabul etme ve doğrudan uygulama erişimi
Bu bölümde, isteğe bağlı olan bir C++/WinRT 2.0 özelliği açıklanmaktadır; ancak bu özellik yeni projelerde varsayılan olarak etkindir. Mevcut bir proje için, cppwinrt.exe aracını yapılandırarak bu özelliği etkinleştirmeniz gerekir. Visual Studio'da,C++/WinRT>için İyileştirilmiş> proje özelliğini Evet olarak ayarlayın. Bu, proje dosyanıza <CppWinRTOptimized>true</CppWinRTOptimized> eklenmesine neden olur. Ayrıca, komut satırından çağrılırken cppwinrt.exe anahtarı eklemeyle aynı etkiye sahiptir.
-opt[imize] seçeneği, genellikle tekbiçimli yapı olarak adlandırılan yapıyı etkinleştirir. Tekdüzen (veya birleşik) yapı ile C++/WinRT dil projeksiyonunu kullanarak uygulama türlerinizi (bileşeniniz tarafından uygulanan türler, uygulamalar tarafından tüketim için) verimli bir şekilde ve herhangi bir yükleyici zoru olmadan oluşturabilir ve kullanabilirsiniz.
Özelliği açıklamadan önce durumu tek tip yapı olmadan gösterelim. Bunu göstermek için bu örnek Windows Çalışma Zamanı sınıfıyla başlayacağız.
// MyClass.idl
namespace MyProject
{
runtimeclass MyClass
{
MyClass();
void Method();
static void StaticMethod();
}
}
C++/WinRT kitaplığını kullanmayı bilen bir C++ geliştiricisi olarak sınıfını bu şekilde kullanmak isteyebilirsiniz.
using namespace winrt::MyProject;
MyClass c;
c.Method();
MyClass::StaticMethod();
Ve gösterilen tüketen kodun bu sınıfı uygulayan aynı bileşende yer almamış olması koşuluyla bu son derece makul olacaktır. Bir dil projeksiyonu olarak, C++/WinRT sizi ABI'den bir geliştirici olarak korur (Windows Çalışma Zamanı tanımladığı COM tabanlı uygulama ikili arabirimi). C++/WinRT doğrudan uygulamaya çağrı yapmaz; ABI'nin içinden geçer.
Sonuç olarak, MyClass nesnesi (MyClass c; ) oluşturduğunuz kod satırında C++/WinRT projeksiyonu, sınıfı veya etkinleştirme fabrikasını almak için RoGetActivationFactory'yi çağırır ve nesneyi oluşturmak için bu fabrikayı kullanır. Aynı şekilde son satır, statik yöntem çağrısı gibi görünen bir şey yapmak için fabrikayı kullanır. Tüm bunlar sınıfınızın kaydedilmesini ve modülünüzün DllGetActivationFactory giriş noktasını uygulamasını gerektirir. C++/WinRT çok hızlı bir fabrika önbelleğine sahip olduğundan, bunların hiçbiri bileşeninizi kullanan bir uygulama için sorun oluşturmaz. Sorun, bileşeninizin içinde biraz sorunlu bir şey yapmış olmanızdır.
İlk olarak, C++/WinRT fabrika önbelleği ne kadar hızlı olursa olsun, RoGetActivationFactory (hatta fabrika önbelleği aracılığıyla yapılan sonraki çağrılar) aracılığıyla çağırmak her zaman doğrudan uygulamaya çağırmaktan daha yavaş olacaktır.
RoGetActivationFactory çağrısı ve ardından IActivationFactory::ActivateInstance ve ardından QueryInterface çağrısı yerel olarak tanımlanmış bir tür için C++ new ifadesi kullanmak kadar verimli olmayacaktır. Sonuç olarak, deneyimli C++/WinRT geliştiricileri bir bileşen içinde nesne oluştururken winrt::make veya winrt::make_self yardımcı işlevlerini kullanmaya alışkındır.
// MyClass c;
MyProject::MyClass c{ winrt::make<implementation::MyClass>() };
Ancak, gördüğünüz gibi, bu kadar kullanışlı veya kısa değil. Nesneyi oluşturmak için bir yardımcı işlev kullanmanız gerekir; ayrıca uygulama türü ile yansıtılan tür arasında açıkça ayrım yapmanız da gerekir.
İkinci olarak, sınıfı oluşturmak için projeksiyonu kullanmak, etkinleştirme fabrikasının önbelleğe alınacağı anlamına gelir. Normalde istediğiniz şey budur, ancak oluşturucu çağrıyı yapan aynı modülde (DLL) yer alıyorsa, DLL’yi fiilen sabitlemiş ve artık hiçbir zaman bellekten boşaltılmasını engellemiş olursunuz. Çoğu durumda, bu önemli değildir; ancak bazı sistem bileşenlerinin kaldırmayı desteklemesi gerekir .
Tek tip inşaat terimi burada devreye girer. Oluşturma kodunun yalnızca sınıfını kullanan bir projede mi yoksa sınıfını gerçekten uygulayan projede mi bulunduğundan bağımsız olarak, nesneyi oluşturmak için aynı söz dizimini serbestçe kullanabilirsiniz.
// MyProject::MyClass c{ winrt::make<implementation::MyClass>() };
MyClass c;
Bileşen projenizi -opt[imize] anahtarıyla derlediğinizde, dil projeksiyonu aracılığıyla yapılan çağrı, doğrudan uygulama türünü oluşturan winrt::make işlevine yapılan aynı verimli çağrıya indirgenir. Bu sayede söz diziminiz basit ve öngörülebilir olur, fabrika üzerinden çağrı yapmanın yol açacağı herhangi bir performans kaybını önler ve bu süreçte bileşenin sabitlenmesini engeller. Bu, bileşen projelerine ek olarak XAML uygulamaları için de yararlıdır. Aynı uygulamada uygulanan sınıflar için RoGetActivationFactory'nin atlanması, bileşeninizin dışında olmaları durumunda bunları mümkün olan tüm yollarla oluşturmanıza olanak tanır (kaydedilmesine gerek kalmadan).
Tekdüzen yapı, fabrikanın arka planda işlediği her çağrı için geçerlidir. Pratikte bu, iyileştirmenin hem oluşturuculara hem de statik üyelere hizmet yaptığı anlamına gelir. İşte bu özgün örnek.
MyClass c;
c.Method();
MyClass::StaticMethod();
-opt[imize] olmadan, ilk ve son ifadeler fabrika nesnesi üzerinden çağrılmasını gerektirir.
İle-opt[imize], ikisi de yapmaz. Ve bu çağrılar doğrudan gerçekleştirimine karşı derlenir, hatta satır içine bile alınabilir. Bu da, -opt[imize] söz konusu olduğunda sıkça kullanılan diğer terime, yani doğrudan uygulama erişimine işaret eder.
Dil projeksiyonları kullanışlıdır, ancak uygulamaya doğrudan erişebildiğinizde, mümkün olan en verimli kodu üretmek için bu avantajdan yararlanabilir ve bundan yararlanmanız gerekir. C++/WinRT, projeksiyonun güvenliğini ve üretkenliğini bırakmaya zorlamadan bunu sizin için yapabilir.
Bu hataya neden olan bir değişikliktir çünkü dil projeksiyonunun uygulama türlerine ulaşmasına ve doğrudan erişmesine izin vermek için bileşenin işbirliği yapması gerekir. C++/WinRT yalnızca üst bilgi kitaplığı olduğundan, içine bakabilir ve neler olduğunu görebilirsiniz.
-opt[imize] olmadan, MyClass yapıcısı ve StaticMethod üyesi projeksiyon tarafından aşağıdaki gibi tanımlanır.
namespace winrt::MyProject
{
inline MyClass::MyClass() :
MyClass(impl::call_factory<MyClass>([](auto&& f){
return f.template ActivateInstance<MyClass>(); }))
{
}
inline void MyClass::StaticMethod()
{
impl::call_factory<MyClass, MyProject::IClassStatics>([&](auto&& f) {
return f.StaticMethod(); });
}
}
Yukarıdakilerin tümünü takip etmek gerekli değildir; amacı, her iki çağrının da call_factory adlı bir işleve çağrı içerdiğini göstermektir. Bu çağrıların fabrika önbelleğini içerdiğine ve uygulamaya doğrudan erişmediklerine dair ipucunuz bu.
Bununla-opt[imize], aynı işlevler hiç tanımlı değildir. Bunun yerine, bunlar projeksiyon tarafından bildirilir ve tanımları bileşene bırakılır.
Bileşen daha sonra doğrudan uygulamaya çağrıda bulunan tanımlar sağlayabilir. Şimdi breaking change’e geldik. Bu tanımlar, hem hem -componentde -opt[imize] kullandığınızda sizin için oluşturulur ve adlı bir dosyada Type.g.cppgörünürler; burada Tür, uygulanan çalışma zamanı sınıfının adıdır. Bu nedenle, mevcut bir projede -opt[imize] seçeneğini ilk kez etkinleştirdiğinizde çeşitli bağlayıcı hatalarıyla karşılaşabilirsiniz. Öğeleri birleştirmeniz için oluşturulan dosyayı uygulamanıza eklemeniz gerekir.
Örneğimizde, MyClass.h bu şekilde görünebilir (kullanılıp kullanılmadığına -opt[imize] bakılmaksızın).
// 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’nız her şeyin bir araya geldiği yerdir.
#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()
{
}
}
Dolayısıyla, mevcut bir projede tek tip yapı kullanmak için, her uygulamanın .cpp dosyasını, uygulama sınıfı eklendikten (ve tanımlandıktan) sonra #include <Sub/Namespace/Type.g.cpp> şekilde düzenlemeniz gerekir. Bu dosya, projeksiyonun tanımsız bıraktığı işlevlerin tanımlarını sağlar. Bu tanımların dosyanın içinde nasıl göründüğü aşağıdadır MyClass.g.cpp .
namespace winrt::MyProject
{
MyClass::MyClass() :
MyClass(make<MyProject::implementation::MyClass>())
{
}
void MyClass::StaticMethod()
{
return MyProject::implementation::MyClass::StaticMethod();
}
}
Bu da, doğrudan uygulamaya yapılan verimli çağrılarla projeksiyonu güzelce tamamlar, fabrika önbelleğine yapılan çağrıları önler ve bağlayıcının gereksinimlerini karşılar.
Sizin için en önemli şey -opt[imize] , projenizin module.g.cpp uygulamasını (DLL'nizin DllGetActivationFactory ve DllCanUnloadNow dışarı aktarmalarını uygulamanıza yardımcı olan dosya) artımlı derlemelerin C++/WinRT 1.0 için gerekli olan güçlü tür bağlamasını ortadan kaldırarak çok daha hızlı olma eğiliminde olacağı şekilde değiştirmektir. Bu genellikle tür silme fabrikaları olarak adlandırılır.
-opt[imize] olmadan, bileşeniniz için oluşturulan module.g.cpp dosyası, bu örnekte MyClass.h olan tüm uygulama sınıflarınızın tanımlarını ekleyerek başlar. Ardından, bunun gibi her sınıf için doğrudan uygulama fabrikasını oluşturur.
if (requal(name, L"MyProject.MyClass"))
{
return winrt::detach_abi(winrt::make<winrt::MyProject::factory_implementation::MyClass>());
}
Yine tüm ayrıntıları izlemeniz gerekmez. Görmeniz yararlı olan, bunun bileşeniniz tarafından uygulanan tüm sınıflar için tam tanımı gerektirmesidir. Bu, iç döngünüz üzerinde çarpıcı bir etkiye sahip olabilir; çünkü tek bir uygulamadaki herhangi bir değişiklik, module.g.cpp öğesinin yeniden derlenmesine neden olur. ile -opt[imize]bu durum artık geçerli değildir. Bunun yerine, oluşturulan module.g.cpp dosyaya iki şey olur. Birincisi, artık herhangi bir uygulama sınıfı içermemiş olmasıdır. Bu örnekte, MyClass.h hiç dahil edilmeyecektir. Bunun yerine, uygulama fabrikalarını uygulamaları hakkında hiçbir bilgi olmadan oluşturur.
void* winrt_make_MyProject_MyClass();
if (requal(name, L"MyProject.MyClass"))
{
return winrt_make_MyProject_MyClass();
}
Açıkçası, tanımlarını eklemeye gerek yoktur ve winrt_make_Component_Class işlevinin tanımını çözümlemek bağlayıcıya bağlı olur. Elbette, bunu dert etmenize gerek yoktur; çünkü sizin için oluşturulan ve daha önce tekdüzen yapıyı desteklemek üzere dahil ettiğiniz MyClass.g.cpp dosyası da bu işlevi tanımlar. Bu örnek için oluşturulan dosyanın tamamı MyClass.g.cpp aşağıda verilmiştir.
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();
}
}
Gördüğünüz gibi winrt_make_MyProject_MyClass işlevi doğrudan uygulamanızın fabrikasını oluşturur. Tüm bunlar, herhangi bir implementasyonu gönül rahatlığıyla değiştirebileceğiniz ve module.g.cpp’ın hiç yeniden derlenmesi gerekmeyeceği anlamına gelir.
module.g.cpp yalnızca Windows Çalışma Zamanı sınıfları eklediğinizde veya kaldırdığınızda güncellenecek ve yeniden derlenmesi gerekecektir.
Temel sınıf sanal yöntemlerini geçersiz kılma
Hem temel sınıf hem de türetilmiş sınıf uygulama tarafından tanımlanan sınıflarsa, ancak sanal yöntem daha üstteki bir Windows Çalışma Zamanı sınıfında tanımlanmışsa, türetilmiş sınıfınızda sanal yöntemlerle ilgili sorunlar olabilir. Uygulamada, XAML sınıflarından türetilirseniz bu durum ortaya çıkar. Bu bölümün geri kalanı Türetilmiş sınıflardaki örnekten devam eder.
namespace winrt::MyNamespace::implementation
{
struct BasePage : BasePageT<BasePage>
{
void OnNavigatedFrom(Microsoft::UI::Xaml::Navigation::NavigationEventArgs const& e);
};
struct DerivedPage : DerivedPageT<DerivedPage>
{
void OnNavigatedFrom(Microsoft::UI::Xaml::Navigation::NavigationEventArgs const& e);
};
}
Hiyerarşi: Microsoft::UI::Xaml::Controls::Page<- BasePage<- DerivedPage. BasePage::OnNavigatedFrom yöntemi Page::OnNavigatedFrom'ı doğru geçersiz kılar, ancak DerivedPage::OnNavigatedFromBasePage::OnNavigatedFrom'ı geçersiz kılmaz.
Burada DerivedPage, BasePage'den IPageOverrides vtable'ını yeniden kullanır; bu da IPageOverrides::OnNavigatedFrom yöntemini geçersiz kılamaması anlamına gelir. Olası çözümlerden biri , BasePage'in kendisinin bir şablon sınıfı olmasını ve uygulamasının tamamen bir üst bilgi dosyasında olmasını gerektirir, ancak bu durum işleri kabul edilemez derecede karmaşık hale getirir.
Geçici bir çözüm olarak , OnNavigatedFrom yöntemini temel sınıfta açıkça sanal olarak bildirin. Bu şekilde, DerivedPage::IPageOverrides::OnNavigatedFrom vtable girdisi BasePage::IPageOverrides::OnNavigatedFrom'ı çağırdığında, producer BasePage::OnNavigatedFrom'ı çağırır; bu da (sanal olması nedeniyle) sonuçta DerivedPage::OnNavigatedFrom'un çağrılmasına yol açar.
namespace winrt::MyNamespace::implementation
{
struct BasePage : BasePageT<BasePage>
{
// Note the `virtual` keyword here.
virtual void OnNavigatedFrom(Microsoft::UI::Xaml::Navigation::NavigationEventArgs const& e);
};
struct DerivedPage : DerivedPageT<DerivedPage>
{
void OnNavigatedFrom(Microsoft::UI::Xaml::Navigation::NavigationEventArgs const& e);
};
}
Bu, sınıf hiyerarşisinin tüm üyelerinin OnNavigatedFrom yönteminin dönüş değeri ve parametre türlerini kabul etmelerini gerektirir. Aynı fikirde değillerse, sanal metot olarak yukarıdaki sürümü kullanın ve alternatifleri sarmalayın.
Note
IDL'nizin geçersiz kılınan yöntemi bildirmesi gerekmez. Daha fazla bilgi için bkz. Geçersiz kılınabilir metotları uygulama.
Önemli API'ler
- winrt::com_ptr yapı şablonu
- winrt::com_ptr::copy_from fonksiyonu
- winrt::from_abi işlev şablonu
- winrt::get_self işlev şablonu
- winrt::implements struct template
- winrt::make işlev şablonu
- winrt::make_self işlev şablonu
- winrt::Windows::Foundation::IUnknown::as fonksiyonu
- winrt::Windows::Foundation::IUnknown::try_as işlevi
İlgili konular
Windows developer