{"id":110916,"date":"2025-02-28T07:00:00","date_gmt":"2025-02-28T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=110916"},"modified":"2025-02-28T07:03:55","modified_gmt":"2025-02-28T15:03:55","slug":"20250228-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250228-00\/?p=110916","title":{"rendered":"C++\/WinRT implementation inheritance: Notes on <CODE>winrt::implements<\/CODE>, part 8"},"content":{"rendered":"<p>We wrap up this series with a comparison of pros and cons.<\/p>\n<p>Deriving your class from <code>winrt::<wbr \/>implements<\/code> means that your declared interfaces will be implemented by anybody who derives from you. This is nice because it removes another point of failure: Forgetting to declare all the interfaces. (For example, if you add a new interface to your class, your derived classes don&#8217;t all have to update.)<\/p>\n<p>On the other hand, declaring the interface in <code>winrt::<wbr \/>implements<\/code> means that your class must implement the entire interface, even if you wanted to delegate some of the methods to the derived class.<\/p>\n<p>You can work around this with a virtual method or by using CRTP. Virtual methods are useful if you can dictate the method signature. CRTP gives the derived class more flexibility in deciding how to implement the method. However, you need to be careful with CRTP to avoid template code explosion.<\/p>\n<p>If you instead choose a traditional C++ base class, then you can implement as much or as little of an interface as you like, and let the derived class implement the rest. The derived class does have to remember to declare the interface in its own <code>winrt::<wbr \/>implements<\/code>, and the same remarks apply as above. Similarly, the same remarks regarding virtual methods and CRTP apply if you want your class to ask the derived class for help.<\/p>\n<p>One case where CRTP is probably the best choice is if you need to call methods on a sibling interface implemented by the derived class.<\/p>\n<pre>template&lt;typename D&gt;\r\nstruct CanHideOnFocusLoss\r\n{\r\n    void HideOnFocusLoss(bool hide = true)\r\n    {\r\n        if (m_hide != hide) {\r\n            m_hide = hide;\r\n            if (m_hide) {\r\n                <span style=\"border: solid 1px currentcolor; border-bottom: none;\">\/\/ Call method on derived class                 <\/span>\r\n                <span style=\"border: 1px currentcolor; border-style: none solid;\">m_lostFocusRevoker = owner()-&gt;LostFocus(        <\/span>\r\n                <span style=\"border: solid 1px currentcolor; border-top: none;\">    { this, &amp;CanHideOnFocusLoss::OnLostFocus });<\/span>\r\n            } else {\r\n                m_lostFocusRevoker.reset();\r\n            }\r\n        }\r\n    }\r\n\r\nprivate:\r\n    winrt::LostFocus_revoker m_lostFocusRevoker;\r\n    bool m_hide = false;\r\n\r\n    D* owner() { return static_cast&lt;D*&gt;(this); }\r\n\r\n    void OnLostFocus(winrt::IInspectable const&amp;,\r\n                     winrt::RoutedEventHandler const&amp;)\r\n    {\r\n        <span style=\"border: solid 1px currentcolor; border-bottom: none;\">\/\/ Call method on derived class<\/span>\r\n        <span style=\"border: solid 1px currentcolor; border-top: none;\">owner()-&gt;Hide();               <\/span>\r\n    }\r\n};\r\n<\/pre>\n<p>The intention is that the implementation of an object that implements a <code>Flyout<\/code> can derive from <code>Can\u00adHide\u00adOn\u00adFocus\u00adLoss&lt;T&gt;<\/code>\u00a0and enable auto-hide on focus loss.<\/p>\n<pre>\/\/ MyProject.idl\r\n\r\nnamespace Contoso\r\n{\r\n    runtimeclass MagicFlyout : Windows.UI.Xaml.Controls.Flyout\r\n    {\r\n        MagicFlyout();\r\n    }\r\n};\r\n\r\n\/\/ MyProject.h\r\n\r\nstruct MagicFlyout :\r\n    MagicFlyoutT&lt;MagicFlyout&gt;,\r\n    <span style=\"border: solid 1px currentcolor;\">CanHideOnFocusLoss&lt;MagicFlyout&gt;<\/span>\r\n{\r\n    MagicFlyout()\r\n    {\r\n        HideOnFocusLoss(true);\r\n    }\r\n};\r\n<\/pre>\n<p>This is sort of a mixin-style base class that lets you attach behaviors to other classes.<\/p>\n<p>The &#8220;deducing this&#8221; feature makes this more ergonomic for consumers, though it&#8217;s more cumbersome for the class itself.<\/p>\n<pre>struct CanHideOnFocusLoss\r\n{\r\n    <span style=\"border: solid 1px currentcolor;\">template&lt;typename D&gt;<\/span>\r\n    void HideOnFocusLoss(<span style=\"border: solid 1px currentcolor;\">this D&amp;&amp; self<\/span>, bool hide = true)\r\n    {\r\n        if (m_hide != hide) {\r\n            m_hide = hide;\r\n            if (m_hide) {\r\n                <span style=\"border: solid 1px currentcolor; border-bottom: none;\">\/\/ Call method on derived class                    <\/span>\r\n                <span style=\"border: 1px currentcolor; border-style: none solid;\">m_lostFocusRevoker = self.LostFocus(               <\/span>\r\n                <span style=\"border: solid 1px currentcolor; border-top: none;\">    { this, &amp;CanHideOnFocusLoss::OnLostFocus&lt;D&gt; });<\/span>\r\n            } else {\r\n                m_lostFocusRevoker.reset();\r\n            }\r\n        }\r\n    }\r\n\r\nprivate:\r\n    winrt::LostFocus_revoker m_lostFocusRevoker;\r\n    bool m_hide = false;\r\n\r\n    <span style=\"border: solid 1px currentcolor;\">template&lt;typename D&gt;<\/span>\r\n    void OnLostFocus(winrt::IInspectable const&amp;,\r\n                     winrt::RoutedEventHandler const&amp;)\r\n    {\r\n        <span style=\"border: solid 1px currentcolor; border-bottom: none;\">\/\/ Call method on derived class<\/span>\r\n        <span style=\"border: solid 1px currentcolor; border-top: none;\">static_cast&lt;D&amp;&amp;&gt;(*this).Hide();<\/span>\r\n    }\r\n};\r\n\r\n\/\/ MyProject.h\r\n\r\nstruct MagicFlyout :\r\n    MagicFlyoutT&lt;MagicFlyout&gt;,\r\n    <span style=\"border: solid 1px currentcolor;\">CanHideOnFocusLoss<\/span>\r\n{\r\n    MagicFlyout()\r\n    {\r\n        HideOnFocusLoss(true);\r\n    }\r\n};\r\n<\/pre>\n<p>This ends a rather tedious discussion of class derivation patterns in C++\/WinRT implementation classes, how you can <code>winrt::<wbr \/>implements<\/code>, and why you might not want to. Most of it is fairly obvious once you get past the C++\/WinRT template metaprogramming, but I felt compelled to write it all out for reference.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Comparing the options.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-110916","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Comparing the options.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110916","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=110916"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110916\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=110916"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=110916"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=110916"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}