Skip to content

Commit 2420f65

Browse files
Document Windows Runtime class derivation in C++/WinRT (#3784)
* Document Windows Runtime class derivation in C++/WinRT Also include information on how to call base class methods. * Update author-apis.md --------- Co-authored-by: Steven White <[email protected]>
1 parent 1138668 commit 2420f65

File tree

1 file changed

+95
-1
lines changed

1 file changed

+95
-1
lines changed

uwp/cpp-and-winrt-apis/author-apis.md

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
description: This topic shows how to author C++/WinRT APIs by using the **winrt::implements** base struct, either directly or indirectly.
33
title: Author APIs with C++/WinRT
4-
ms.date: 07/08/2019
4+
ms.date: 09/22/2023
55
ms.topic: article
66
keywords: windows 10, uwp, standard, c++, cpp, winrt, projected, projection, implementation, implement, runtime class, activation
77
ms.localizationpriority: medium
@@ -401,6 +401,100 @@ void FreeFunction(MyProject::MyOtherClass const& oc)
401401
...
402402
```
403403

404+
## Runtime class derivation
405+
406+
You can create a runtime class that derives from another runtime class, provided that the base class is declared as "unsealed". The Windows Runtime term for class derivation is "composable classes". The code for implementing a derived class depends on whether the base class is provided by another component or by the same component. Fortunately, you don't have to learn these rules&mdash;you can just copy the sample implementations from the `sources` output folder produced by the `cppwinrt.exe` compiler.
407+
408+
Consider this example.
409+
410+
```idl
411+
// MyProject.idl
412+
namespace MyProject
413+
{
414+
[default_interface]
415+
runtimeclass MyButton : Windows.UI.Xaml.Controls.Button
416+
{
417+
MyButton();
418+
}
419+
420+
unsealed runtimeclass MyBase
421+
{
422+
MyBase();
423+
overridable Int32 MethodOverride();
424+
}
425+
426+
[default_interface]
427+
runtimeclass MyDerived : MyBase
428+
{
429+
MyDerived();
430+
}
431+
}
432+
```
433+
434+
In the above example, **MyButton** is derived from the XAML **Button** control, which is provided by another component. In that case, the implementation looks just like the implementation of a non-composable class:
435+
436+
```cpp
437+
namespace winrt::MyProject::implementation
438+
{
439+
struct MyButton : MyButtonT<MyButton>
440+
{
441+
};
442+
}
443+
444+
namespace winrt::MyProject::factory_implementation
445+
{
446+
struct MyButton : MyButtonT<MyButton, implementation::MyButton>
447+
{
448+
};
449+
}
450+
```
451+
452+
On the other hand, in the above example, **MyDerived** is derived from another class in the same component. In this case, the implementation requires an additional template parameter specifying the implementation class for the base class.
453+
454+
```cpp
455+
namespace winrt::MyProject::implementation
456+
{
457+
struct MyDerived : MyDerivedT<MyDerived, implementation::MyBase>
458+
{ // ^^^^^^^^^^^^^^^^^^^^^^
459+
};
460+
}
461+
462+
namespace winrt::MyProject::factory_implementation
463+
{
464+
struct MyDerived : MyDerivedT<MyDerived, implementation::MyDerived>
465+
{
466+
};
467+
}
468+
```
469+
470+
In either case, your implementation can call a method from the base class by qualifying it with the `base_type` type alias:
471+
472+
```cpp
473+
namespace winrt::MyProject::implementation
474+
{
475+
struct MyButton : MyButtonT<MyButton>
476+
{
477+
void OnApplyTemplate()
478+
{
479+
// Call base class method
480+
base_type::OnApplyTemplate();
481+
482+
// Do more work after the base class method is done
483+
DoAdditionalWork();
484+
}
485+
};
486+
487+
struct MyDerived : MyDerivedT<MyDerived, implementation::MyBase>
488+
{
489+
int MethodOverride()
490+
{
491+
// Return double what the base class returns
492+
return 2 * base_type::MethodOverride();
493+
}
494+
};
495+
}
496+
```
497+
404498
## Deriving from a type that has a non-default constructor
405499

406500
[**ToggleButtonAutomationPeer::ToggleButtonAutomationPeer(ToggleButton)**](/uwp/api/windows.ui.xaml.automation.peers.togglebuttonautomationpeer.-ctor#Windows_UI_Xaml_Automation_Peers_ToggleButtonAutomationPeer__ctor_Windows_UI_Xaml_Controls_Primitives_ToggleButton_) is an example of a non-default constructor. There's no default constructor so, to construct a **ToggleButtonAutomationPeer**, you need to pass an *owner*. Consequently, if you derive from **ToggleButtonAutomationPeer**, then you need to provide a constructor that takes an *owner* and passes it to the base. Let's see what that looks like in practice.

0 commit comments

Comments
 (0)