Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <h1>Checking Interface.</h1> <p>Dynamic polymorphism does force the child to respect the interface.</p> <p>Static polymorphism does NOT force the child to respect the interface (until you really call the function), So, if you don't provide useful method, you may use directly <code>Impl</code>.</p> <pre><code>class InvalidImpl {}; // Doesn't respect interface. void bar() { InvalidImpl invalid; // this compiles, as not "expected" since InvalidImpl doesn't respect Interface. CRTP_Interface&lt;InvalidImpl&gt; crtp_invalid; #if 0 // Any lines of following compile as expected. invalid.Foo(); crtp_invalid.Foo(); #endif } </code></pre> <p>You have a 3rd way using traits to check that a class verify an Interface:</p> <pre><code>#include &lt;cstdint&gt; #include &lt;type_traits&gt; // Helper macro to create traits class to know if class has a member method #define HAS_MEM_FUNC(name, Prototype, func) \ template&lt;typename U&gt; \ struct name { \ typedef std::uint8_t yes; \ typedef std::uint16_t no; \ template &lt;typename T, T&gt; struct type_check; \ template &lt;typename T = U&gt; \ static yes &amp;chk(type_check&lt;Prototype, &amp;T::func&gt; *); \ template &lt;typename &gt; static no &amp;chk(...); \ static constexpr bool value = sizeof(chk&lt;U&gt;(0)) == sizeof(yes); \ } // Create traits has_Foo. HAS_MEM_FUNC(has_Foo, void (T::*)(), Foo); // Aggregate all requirements for Interface template &lt;typename T&gt; struct check_Interface : std::integral_constant&lt;bool, has_Foo&lt;T&gt;::value /* &amp;&amp; has_otherMethod&lt;T&gt;::value */&gt; {}; // Helper macros to assert if class does respect interface or not. #define CHECK_INTERFACE(T) static_assert(check_Interface&lt;T&gt;::value, #T " doesn't respect the interface") #define CHECK_NOT_INTERFACE(T) static_assert(!check_Interface&lt;T&gt;::value, #T " does respect the interface") </code></pre> <p>Lets test it:</p> <pre><code>class Interface { public: virtual void Foo() = 0; }; class Child_Impl final : public Interface { public: void Foo() override {}; }; #if 0 // Following doesn't compile as expected. class Child_InvalidImpl final : public Interface {}; #endif template &lt;class I&gt; class CRTP_Interface : public I { public: void Foo() { I::Foo(); } // not actually needed }; class Impl { public: void Foo(); }; // Do respect interface. class InvalidImpl {}; // Doesn't respect interface. CHECK_INTERFACE(Interface); CHECK_INTERFACE(Child_Impl); CHECK_INTERFACE(Impl); CHECK_INTERFACE(CRTP_Interface&lt;Impl&gt;); CHECK_NOT_INTERFACE(InvalidImpl); CHECK_INTERFACE(CRTP_Interface&lt;InvalidImpl&gt;); // CRTP_Interface&lt;T&gt; _HAS_ Foo (which cannot be invoked) </code></pre> <h1>Performance</h1> <p>With Dynamic Polymorphism, you may pay for virtual call. You may reduce some virtual call by adding <code>final</code> as <code>class Child final : public Interface</code>.</p> <p>So compiler may optimize code like:</p> <pre><code>void bar(Child&amp; child) { child.Foo(); } // may call Child::Foo not virtually. </code></pre> <p>but it can't do any magic (assuming <code>bar</code> not inlined) with:</p> <pre><code>void bar(Interface&amp; child) { child.Foo(); } // have to virtual call Foo. </code></pre> <p>Now, assume that in your interface you have:</p> <pre><code>void Interface::Bar() { /* some code */ Foo(); } </code></pre> <p>we are in the second case where we have to virtual call <code>Foo</code>.</p> <p>Static polymorphism solves that by:</p> <pre><code>template&lt;class Derived&gt; void Interface&lt;Derived&gt;::Bar() { /* some code */ static_cast&lt;Derived*&gt;(this)-&gt;Foo(); } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload