On forcing all derived classes to implement a specific non-virtual method, part 1

The Old New Thing (Raymond Chen) News

Summary

The article discusses techniques in C++ to enforce derived classes to implement a specific non-virtual method, using examples from C++/WRL and C++/WinRT, and critiques a code review scenario where comments were used instead of proper enforcement.

<p>You may have a base class that implements only partial functionality and relies on the derived class to do the rest. How do you make sure that the derived class does the rest?</p> <p>For concreteness, let&#8217;s say that we are implementing <code>IValueConverter</code>, which has two methods:</p> <ul> <li><code>Convert()</code> to convert from the source to the destination.</li> <li><code>ConvertBack()</code> so that two-way conversions can convert from the destination to the source.</li> </ul> <p>Suppose you want to write a base class called <code>OneWayConverter</code>. Its implementation fails the <code>ConvertBack()</code> call, and you want to force the derived class to implement the forward conversion.</p> <pre>// C++/WRL struct WidgetColorConverter : Microsoft::WRL::RuntimeClass&lt; Microsoft::WRL::RuntimeClassFlags&lt;Microsoft::WRL::WinRt&gt;, ABI::Windows::UI::Xaml::Data::IValueConverter&gt;, OneWayConverter { // Require the derived class to implement Convert somehow HRESULT STDMETHODCALLTYPE Convert(IInspectable* value, ABI::Windows::UI::Xaml::Interop::TypeName targetType, IInspectable* parameter, HSTRING language, IInspectable** result) { ⟦ ... ⟧ } }; // C++/WinRT struct WidgetColorConverter : winrt::implements&lt;WidgetColorConverter&gt;, OneWayConverter { // Require the derived class to implement Convert somehow winrt::Windows::Foundation::IInspectable Convert( winrt::Windows::Foundation::IInspectable const&amp; value, winrt::Windows::UI::Xaml::Interop::TypeName const&amp; targetType, winrt::Windows::Foundation::IInspectable const&amp; parameter, winrt::hstring const&amp; language) { ⟦ ... ⟧ } } // Plain C++ analogous scenario struct WidgetColorConverter : OneWayConverter { // Require the derived class to implement Convert somehow Color Convert(Widget const&amp;amp value) { ⟦ ... ⟧ } }; </pre> <p>During a code review, I saw that somebody tried to do this just by writing a comment.</p> <pre>// C++/WRL struct OneWayConverter { // Derived classes must override this method. HRESULT STDMETHODCALLTYPE Convert(IInspectable* /*value*/, ABI::Windows::UI::Xaml::Interop::TypeName /*targetType*/, IInspectable* /*parameter*/, HSTRING /*language*/, IInspectable** result) { assert(false); *result = nullptr; return E_NOTIMPL; } // One-way converters cannot convert back HRESULT STDMETHODCALLTYPE ConvertBack(IInspectable* /*value*/, ABI::Windows::UI::Xaml::Interop::TypeName /*targetType*/, IInspectable* /*parameter*/, HSTRING /*language*/, IInspectable** result) { *result = nullptr; return E_NOTIMPL; } }; // C++/WinRT struct OneWayConverter { // Derived classes must override this method. winrt::Windows::Foundation::IInspectable Convert( winrt::Windows::Foundation::IInspectable const&amp; /*value*/, winrt::Windows::UI::Xaml::Interop::TypeName const&amp; /*targetType*/, winrt::Windows::Foundation::IInspectable const&amp; /*parameter*/, winrt::hstring const&amp; /*language*/) { assert(false); throw winrt::hresult_not_implemented(); } // One-way converters cannot convert back winrt::Windows::Foundation::IInspectable ConvertBack( winrt::Windows::Foundation::IInspectable const&amp; /*value*/, winrt::Windows::UI::Xaml::Interop::TypeName const&amp; /*targetType*/, winrt::Windows::Foundation::IInspectable const&amp; /*parameter*/, winrt::hstring const&amp; /*language*/) { throw winrt::hresult_not_implemented(); } }; // Plain C++ analogous scenario struct OneWayConverter { // Derived classes must override this method. Color Convert(Widget const&amp;amp /*value*/) { assert(false); throw std::exception("not implemented"); } // One-way converters cannot convert back Widget ConvertBack(Color const&amp; /*color*/) { throw std::exception("not implemented"); } }; </pre> <p>I pointed out that they were doing too much work.</p> <p>The way to force somebody to implement a method in the derived class is simply not to implement the method in the base class in the first place.</p> <pre>// C++/WRL struct OneWayConverter { // Derived classes must implement Convert() // One-way converters cannot convert back HRESULT STDMETHODCALLTYPE ConvertBack(IInspectable* /*value*/, ABI::Windows::UI::Xaml::Interop::TypeName /*targetType*/, IInspectable* /*parameter*/, HSTRING /*language*/, IInspectable** result) { *result = nullptr; return E_NOTIMPL; } }; // C++/WinRT struct OneWayConverter { // Derived classes must implement Convert() // One-way converters cannot convert back winrt::Windows::Foundation::IInspectable ConvertBack( winrt::Windows::Foundation::IInspectable const&amp; /*value*/, winrt::Windows::UI::Xaml::Interop::TypeName const&amp; /*targetType*/, winrt::Windows::Foundation::IInspectable const&amp; /*parameter*/, winrt::hstring const&amp; /*language*/) { throw winrt::hresult_not_implemented(); } }; // Plain C++ analogous scenario struct OneWayConverter { // Derived classes must implement Convert() // One-way converters cannot convert back Widget ConvertBack(Color const&amp; /*color*/) { throw std::exception("not implemented"); } }; </pre> <p>The error message if they forget to implement it depends on the library.</p> <pre>// C++/WRL struct WidgetColorConverter : Microsoft::WRL::RuntimeClass&lt; Microsoft::WRL::RuntimeClassFlags&lt;Microsoft::WRL::WinRt&gt;, OneWayConverter&gt; { // Oops, forgot to implement Convert() }; </pre> <p>The error occurs when you call <code>WRL::<wbr />Make</code> to try to create the defective <code>Widget­Color­Converter</code>.</p> <pre style="white-space: pre-wrap;">wrl\implements.h(2512,32): error C2259: 'WidgetColorConverter': cannot instantiate abstract class see declaration of 'WidgetColorConverter' due to following members: wrl\implements.h(2512,32): 'HRESULT ABI::<wbr />Windows::<wbr />UI::<wbr />Xaml::<wbr />Data::<wbr />IValueConverter::<wbr />Convert(IInspectable *,ABI::<wbr />Windows::<wbr />UI::<wbr />Xaml::<wbr />Interop::<wbr />TypeName,<wbr />IInspectable *,<wbr />HSTRING,<wbr />IInspectable **)': is abstract windows.ui.xaml.data.h(2778,59): see declaration of 'ABI::<wbr />Windows::<wbr />UI::<wbr />Xaml::<wbr />Data::<wbr />IValueConverter::<wbr />Convert' wrl\implements.h(2512,32): the template instantiation context (the oldest one first) is test(41,30): see reference to function template instantiation 'Microsoft::<wbr />WRL::<wbr />ComPtr&lt;<wbr />WidgetColorConverter&gt; Microsoft::<wbr />WRL::<wbr />Details::<wbr />Make&lt;WidgetColorConverter,&gt;(void)' being compiled </pre> <p>&#8220;Cannot instantiate abstract class due to the following members&#8221; is the standard error for failing to implement all the necessary pure virtual methods inherited from a base class, so one could expect that people who encounter this error will understand what it means.</p> <pre>// C++/WinRT struct WidgetColorConverter : winrt::implements&lt;WidgetColorConverter, winrt::Windows::UI::Xaml::Data::IValueConverter&gt;, OneWayConverter { // Oops, forgot to implement Convert() }; </pre> <p>The error occurs when you call <code>winrt::<wbr />make</code> to try to create the defective <code>Widget­Color­Converter</code>.</p> <pre style="white-space: pre-wrap;">windows.ui.xaml.data.h(1469,90): error C2039: 'Convert': is not a member of 'WidgetColorConverter' test.cpp(66,8): see declaration of 'WidgetColorConverter' windows.ui.xaml.data.h(1469,90): the template instantiation context (the oldest one first) is test.cpp(66,31): see reference to class template instantiation 'winrt::<wbr />implements&lt;WidgetColorConverter,<wbr />winrt::<wbr />Windows::<wbr />UI::<wbr />Xaml::<wbr />Data::<wbr />IValueConverter&gt;' being compiled winrt\base.h(8088,31): see reference to class template instantiation 'winrt::<wbr />impl::<wbr />producers_base&lt;D,<wbr />std::tuple&lt;<wbr />winrt::<wbr />Windows::<wbr />UI::<wbr />Xaml::<wbr />Data::<wbr />IValueConverter&gt;&gt;' being compiled with [ D=WidgetColorConverter ] winrt\base.h(6763,50): see reference to class template instantiation 'winrt::<wbr />impl::<wbr />producer_convert&lt;D,<wbr />winrt::<wbr />Windows::<wbr />UI::<wbr />Xaml::<wbr />Data::<wbr />IValueConverter,<wbr />void&gt;' being compiled with [ D=WidgetColorConverter ] winrt\base.h(6734,31): see reference to class template instantiation 'winrt::<wbr />impl::<wbr />producer&lt;D,<wbr />winrt::<wbr />Windows::<wbr />UI::<wbr />Xaml::<wbr />Data::<wbr />IValueConverter,<wbr />void&gt;' being compiled with [ D=WidgetColorConverter ] winrt\base.h(7137,23): see reference to class template instantiation 'winrt::<wbr />impl::<wbr />produce&lt;D,I&gt;' being compiled with [ D=WidgetColorConverter, I=winrt::<wbr />Windows::<wbr />UI::<wbr />Xaml::<wbr />Data::<wbr />IValueConverter ] winrt\windows.ui.xaml.data.h(1465,32): while compiling class template member function 'int32_t winrt::<wbr />impl::<wbr />produce&lt;D,I&gt;::<wbr />Convert(<wbr />void *,<wbr />winrt::<wbr />impl::<wbr />struct_<wbr />Windows_<wbr />UI_<wbr />Xaml_<wbr />Interop_<wbr />TypeName,<wbr />void *,<wbr />void *,<wbr />void **) noexcept' with [ D=WidgetColorConverter, I=winrt::<wbr />Windows::<wbr />UI::<wbr />Xaml::<wbr />Data::<wbr />IValueConverter ] </pre> <p>&#8220;⟦Name⟧ is not a member of&#8221; is typical of a CRTP error, since the template is trying to call a method on the derived class, but it&#8217;s not there. Again, one could expect that people who encounter this error will understand what it means.</p> <p>For the plain C++ case, you might have this:</p> <pre>// Plain C++ analogous scenario struct WidgetColorConverter : OneWayConverter { // Oops, forgot to implement Convert() }; </pre> <p>And everything works great until somebody tries to call the <code>Convert</code> method on a <code>Widget­Color­Converter</code> and it&#8217;s not there.</p> <pre style="white-space: pre-wrap;">test.cpp(79,20): error C2039: 'Convert': is not a member of 'WidgetColorConverter' </pre> <p>Again, this is a common error in C++ so you would hope that people understand what it means.</p> <p>Great, so we were able to convert all of these authoring errors into compile-time errors, thereby avoiding the danger that somebody will use the base class and fail to implement all of the expected methods.</p> <p>But wait, we can do better. We&#8217;ll look at this some more next time.</p> <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260827-00/?p=112651">On forcing all derived classes to implement a specific non-virtual method, part 1</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
Original Article
View Cached Full Text

Cached at: 08/28/26, 03:50 PM

# On forcing all derived classes to implement a specific non-virtual method, part 1 - The Old New Thing Source: [https://devblogs.microsoft.com/oldnewthing/20260827-00?p=112651](https://devblogs.microsoft.com/oldnewthing/20260827-00?p=112651) You may have a base class that implements only partial functionality and relies on the derived class to do the rest\. How do you make sure that the derived class does the rest? For concreteness, let’s say that we are implementing`IValueConverter`, which has two methods: - `Convert\(\)`to convert from the source to the destination\. - `ConvertBack\(\)`so that two\-way conversions can convert from the destination to the source\. Suppose you want to write a base class called`OneWayConverter`\. Its implementation fails the`ConvertBack\(\)`call, and you want to force the derived class to implement the forward conversion\. ``` // C++/WRL struct WidgetColorConverter : Microsoft::WRL::RuntimeClass< Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::WinRt>, ABI::Windows::UI::Xaml::Data::IValueConverter>, OneWayConverter { // Require the derived class to implement Convert somehow HRESULT STDMETHODCALLTYPE Convert(IInspectable* value, ABI::Windows::UI::Xaml::Interop::TypeName targetType, IInspectable* parameter, HSTRING language, IInspectable** result) { ⟦ ... ⟧ } }; // C++/WinRT struct WidgetColorConverter : winrt::implements<WidgetColorConverter>, OneWayConverter { // Require the derived class to implement Convert somehow winrt::Windows::Foundation::IInspectable Convert( winrt::Windows::Foundation::IInspectable const& value, winrt::Windows::UI::Xaml::Interop::TypeName const& targetType, winrt::Windows::Foundation::IInspectable const& parameter, winrt::hstring const& language) { ⟦ ... ⟧ } } // Plain C++ analogous scenario struct WidgetColorConverter : OneWayConverter { // Require the derived class to implement Convert somehow Color Convert(Widget const&amp value) { ⟦ ... ⟧ } }; ``` During a code review, I saw that somebody tried to do this just by writing a comment\. ``` // C++/WRL struct OneWayConverter { // Derived classes must override this method. HRESULT STDMETHODCALLTYPE Convert(IInspectable* /*value*/, ABI::Windows::UI::Xaml::Interop::TypeName /*targetType*/, IInspectable* /*parameter*/, HSTRING /*language*/, IInspectable** result) { assert(false); *result = nullptr; return E_NOTIMPL; } // One-way converters cannot convert back HRESULT STDMETHODCALLTYPE ConvertBack(IInspectable* /*value*/, ABI::Windows::UI::Xaml::Interop::TypeName /*targetType*/, IInspectable* /*parameter*/, HSTRING /*language*/, IInspectable** result) { *result = nullptr; return E_NOTIMPL; } }; // C++/WinRT struct OneWayConverter { // Derived classes must override this method. winrt::Windows::Foundation::IInspectable Convert( winrt::Windows::Foundation::IInspectable const& /*value*/, winrt::Windows::UI::Xaml::Interop::TypeName const& /*targetType*/, winrt::Windows::Foundation::IInspectable const& /*parameter*/, winrt::hstring const& /*language*/) { assert(false); throw winrt::hresult_not_implemented(); } // One-way converters cannot convert back winrt::Windows::Foundation::IInspectable ConvertBack( winrt::Windows::Foundation::IInspectable const& /*value*/, winrt::Windows::UI::Xaml::Interop::TypeName const& /*targetType*/, winrt::Windows::Foundation::IInspectable const& /*parameter*/, winrt::hstring const& /*language*/) { throw winrt::hresult_not_implemented(); } }; // Plain C++ analogous scenario struct OneWayConverter { // Derived classes must override this method. Color Convert(Widget const&amp /*value*/) { assert(false); throw std::exception("not implemented"); } // One-way converters cannot convert back Widget ConvertBack(Color const& /*color*/) { throw std::exception("not implemented"); } }; ``` I pointed out that they were doing too much work\. The way to force somebody to implement a method in the derived class is simply not to implement the method in the base class in the first place\. ``` // C++/WRL struct OneWayConverter { // Derived classes must implement Convert() // One-way converters cannot convert back HRESULT STDMETHODCALLTYPE ConvertBack(IInspectable* /*value*/, ABI::Windows::UI::Xaml::Interop::TypeName /*targetType*/, IInspectable* /*parameter*/, HSTRING /*language*/, IInspectable** result) { *result = nullptr; return E_NOTIMPL; } }; // C++/WinRT struct OneWayConverter { // Derived classes must implement Convert() // One-way converters cannot convert back winrt::Windows::Foundation::IInspectable ConvertBack( winrt::Windows::Foundation::IInspectable const& /*value*/, winrt::Windows::UI::Xaml::Interop::TypeName const& /*targetType*/, winrt::Windows::Foundation::IInspectable const& /*parameter*/, winrt::hstring const& /*language*/) { throw winrt::hresult_not_implemented(); } }; // Plain C++ analogous scenario struct OneWayConverter { // Derived classes must implement Convert() // One-way converters cannot convert back Widget ConvertBack(Color const& /*color*/) { throw std::exception("not implemented"); } }; ``` The error message if they forget to implement it depends on the library\. ``` // C++/WRL struct WidgetColorConverter : Microsoft::WRL::RuntimeClass< Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::WinRt>, OneWayConverter> { // Oops, forgot to implement Convert() }; ``` The error occurs when you call`WRL::Make`to try to create the defective`Widget­Color­Converter`\. ``` wrl\implements.h(2512,32): error C2259: 'WidgetColorConverter': cannot instantiate abstract class see declaration of 'WidgetColorConverter' due to following members: wrl\implements.h(2512,32): 'HRESULT ABI::Windows::UI::Xaml::Data::IValueConverter::Convert(IInspectable *,ABI::Windows::UI::Xaml::Interop::TypeName,IInspectable *,HSTRING,IInspectable **)': is abstract windows.ui.xaml.data.h(2778,59): see declaration of 'ABI::Windows::UI::Xaml::Data::IValueConverter::Convert' wrl\implements.h(2512,32): the template instantiation context (the oldest one first) is test(41,30): see reference to function template instantiation 'Microsoft::WRL::ComPtr<WidgetColorConverter> Microsoft::WRL::Details::Make<WidgetColorConverter,>(void)' being compiled ``` “Cannot instantiate abstract class due to the following members” is the standard error for failing to implement all the necessary pure virtual methods inherited from a base class, so one could expect that people who encounter this error will understand what it means\. ``` // C++/WinRT struct WidgetColorConverter : winrt::implements<WidgetColorConverter, winrt::Windows::UI::Xaml::Data::IValueConverter>, OneWayConverter { // Oops, forgot to implement Convert() }; ``` The error occurs when you call`winrt::make`to try to create the defective`Widget­Color­Converter`\. ``` windows.ui.xaml.data.h(1469,90): error C2039: 'Convert': is not a member of 'WidgetColorConverter' test.cpp(66,8): see declaration of 'WidgetColorConverter' windows.ui.xaml.data.h(1469,90): the template instantiation context (the oldest one first) is test.cpp(66,31): see reference to class template instantiation 'winrt::implements<WidgetColorConverter,winrt::Windows::UI::Xaml::Data::IValueConverter>' being compiled winrt\base.h(8088,31): see reference to class template instantiation 'winrt::impl::producers_base<D,std::tuple<winrt::Windows::UI::Xaml::Data::IValueConverter>>' being compiled with [ D=WidgetColorConverter ] winrt\base.h(6763,50): see reference to class template instantiation 'winrt::impl::producer_convert<D,winrt::Windows::UI::Xaml::Data::IValueConverter,void>' being compiled with [ D=WidgetColorConverter ] winrt\base.h(6734,31): see reference to class template instantiation 'winrt::impl::producer<D,winrt::Windows::UI::Xaml::Data::IValueConverter,void>' being compiled with [ D=WidgetColorConverter ] winrt\base.h(7137,23): see reference to class template instantiation 'winrt::impl::produce<D,I>' being compiled with [ D=WidgetColorConverter, I=winrt::Windows::UI::Xaml::Data::IValueConverter ] winrt\windows.ui.xaml.data.h(1465,32): while compiling class template member function 'int32_t winrt::impl::produce<D,I>::Convert(void *,winrt::impl::struct_Windows_UI_Xaml_Interop_TypeName,void *,void *,void **) noexcept' with [ D=WidgetColorConverter, I=winrt::Windows::UI::Xaml::Data::IValueConverter ] ``` “⟦Name⟧ is not a member of” is typical of a CRTP error, since the template is trying to call a method on the derived class, but it’s not there\. Again, one could expect that people who encounter this error will understand what it means\. For the plain C\+\+ case, you might have this: ``` // Plain C++ analogous scenario struct WidgetColorConverter : OneWayConverter { // Oops, forgot to implement Convert() }; ``` And everything works great until somebody tries to call the`Convert`method on a`Widget­Color­Converter`and it’s not there\. ``` test.cpp(79,20): error C2039: 'Convert': is not a member of 'WidgetColorConverter' ``` Again, this is a common error in C\+\+ so you would hope that people understand what it means\. Great, so we were able to convert all of these authoring errors into compile\-time errors, thereby avoiding the danger that somebody will use the base class and fail to implement all of the expected methods\. But wait, we can do better\. We’ll look at this some more next time\. ### Category ### Topics ## Author ![Raymond Chen](https://devblogs.microsoft.com/oldnewthing/wp-content/uploads/sites/38/2019/02/RaymondChen_5in-150x150.jpg) Raymond has been involved in the evolution of Windows for more than 30 years\. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie\-jeebies\. The Web site spawned a book, coincidentally also titled The Old New Thing \(Addison Wesley 2007\)\. He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information\.

Similar Articles