|
1 | 1 | ---
|
2 | 2 | description: This topic shows how to author C++/WinRT APIs by using the **winrt::implements** base struct, either directly or indirectly.
|
3 | 3 | title: Author APIs with C++/WinRT
|
4 |
| -ms.date: 07/08/2019 |
| 4 | +ms.date: 09/22/2023 |
5 | 5 | ms.topic: article
|
6 | 6 | keywords: windows 10, uwp, standard, c++, cpp, winrt, projected, projection, implementation, implement, runtime class, activation
|
7 | 7 | ms.localizationpriority: medium
|
@@ -401,6 +401,100 @@ void FreeFunction(MyProject::MyOtherClass const& oc)
|
401 | 401 | ...
|
402 | 402 | ```
|
403 | 403 |
|
| 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—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 | + |
404 | 498 | ## Deriving from a type that has a non-default constructor
|
405 | 499 |
|
406 | 500 | [**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