August 27th, 2026
intriguinglike2 reactions

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

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.

Topics

Author

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.

0 comments