Elly Fong-Jones | 4e3d25c7 | 2019-08-12 18:17:15 | [diff] [blame^] | 1 | # The Passkey Pattern |
| 2 | |
| 3 | The Passkey pattern is used when you need to expose a subset of a class's |
| 4 | methods to another class in a more granular way than simply friending the other |
| 5 | class. In essence, it involves creating a "passkey" class that can only be |
| 6 | constructed by specific other classes, and requiring an instance of that passkey |
| 7 | class to be passed in when calling methods you wish to restrict the use of. It |
| 8 | is used like this: |
| 9 | |
| 10 | ``` |
| 11 | class Foo { |
| 12 | public: |
| 13 | Foo(); |
| 14 | ~Foo(); |
| 15 | |
| 16 | void NormalPublicMethod(); |
| 17 | bool AnotherNormalPublicMethod(int a, int b); |
| 18 | |
| 19 | class BarPasskey { |
| 20 | private: |
| 21 | friend class Bar; |
| 22 | BarPasskey() = default; |
| 23 | ~BarPasskey() = default; |
| 24 | }; |
| 25 | |
| 26 | void HelpBarOut(BarPasskey, ...); |
| 27 | }; |
| 28 | |
| 29 | ... |
| 30 | |
| 31 | void Bar::DoStuff() { |
| 32 | foo->HelpBarOut(Foo::BarPasskey(), ...); |
| 33 | } |
| 34 | ``` |
| 35 | |
| 36 | The private constructor on `Foo::BarPasskey` prevents any class other than `Bar` |
| 37 | from constructing a `Foo::BarPasskey`, which means that: |
| 38 | |
| 39 | * Only `Bar` can call those methods |
| 40 | * `Bar` can delegate the ability to call those methods to other |
| 41 | classes/functions by passing them a `Foo::BarPasskey` instance |
| 42 | |
| 43 | This method is effectively free at runtime - a few extra bytes of argument space |
| 44 | are used to pass in the Passkey object. |
| 45 | |
| 46 | It is encouraged to leave the `BarPasskey` parameter unnamed to reinforce that it |
| 47 | carries no semantic information and is not actually used for anything. |