Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>As Xeo says, you probably shouldn't do this in this particular case - better design alternatives exist. That said, you <em>can</em> do it with RTTI, but it's generally frowned upon because your <code>process()</code> becomes a centralised maintenance point that needs to be updated as new derived classes are added. That's easily overlooked and prone to run-time errors.</p> <p>If you <em>must</em> persue this for some reason, then at least generalise the facility so a single function uses RTTI-based runtime type determination to invoke arbitrary behaviour, as in:</p> <pre><code>#include &lt;iostream&gt; #include &lt;stdexcept&gt; struct Base { virtual ~Base() { } template &lt;class Op&gt; void for_rt_type(Op&amp; op); }; struct Derived1 : Base { void f() { std::cout &lt;&lt; "Derived1::f()\n"; } }; struct Derived2 : Base { void f() { std::cout &lt;&lt; "Derived2::f()\n"; } }; template &lt;class Op&gt; void Base::for_rt_type(Op&amp; op) { if (Derived1* p = dynamic_cast&lt;Derived1*&gt;(this)) op(p); else if (Derived2* p = dynamic_cast&lt;Derived2*&gt;(this)) op(p); else throw std::runtime_error("unmatched dynamic type"); } struct Op { template &lt;typename T&gt; void operator()(T* p) { p-&gt;f(); } }; int main() { Derived1 d1; Derived2 d2; Base* p1 = &amp;d1; Base* p2 = &amp;d2; Op op; p1-&gt;for_rt_type(op); p2-&gt;for_rt_type(op); } </code></pre> <p>In the code above, you can substitute your own Op and have the same runtime-to-compiletime handover take place. It may or may not help to think of this as a factory method in reverse :-}.</p> <p>As discussed, <code>for_rt_type</code> has to be updated for each derived type: particularly painful if one team "owns" the base class and other teams write derived classes. As with a lot of slightly hacky things, it's more practical and maintainable in support of private implementation rather than as an API feature of a low-level enterprise library. Wanting to use this is still <em>typically</em> a sign of bad design elsewhere, but <em>not</em> always: occasionally there are algorithms (<code>Op</code>s) that benefit enormously:</p> <ul> <li>compile-time optimisations, dead code removal etc.</li> <li>derived types only need same semantics, but details can vary <ul> <li>e.g. <code>Derived1::value_type</code> is <code>int</code>, <code>Derived2::value_type</code> is <code>double</code> - allows algorithms for each to be efficient and use appropriate rounding etc.. Similarly for different container types where only a shared API is exercised.</li> </ul></li> <li>you can use template metaprogramming, SFINAE etc. to customise the behaviours in a derived-type specific way</li> </ul> <p>Personally, I think knowledge of and ability to apply this technique (however rarely) is an important part of mastering polymorphism.</p>
 

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