Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The academic answer would be that in <em>object oriented design</em> you should not depend on the <em>implementation</em> i.e. concrete classes. Instead you should depend on high-level components like <em>interfaces</em> and <em>abstract base classes</em>. You can read more about this <a href="http://en.wikipedia.org/wiki/Dependency_inversion_principle" rel="nofollow">design principle on Wikipedia</a>.</p> <p>The reason for this is to <em>decouple</em> the design which makes the code more manageable and maintainable.</p> <p>Let's look at an example. You have a base class and a derived class:</p> <pre><code>struct Duck { virtual ~Duck() {} }; struct MallardDuck : public Duck { void quack() const { std::cout &lt;&lt; "Quack!" &lt;&lt; std::endl; } }; </code></pre> <p>Let's say you have another class with a function taking a parameter <code>Duck</code>.</p> <pre><code>struct SoundMaker { void makeSound(const Duck* d) { if (const MallardDuck* md = dynamic_cast&lt;const MallardDuck*&gt;(d)) { md-&gt;quack(); } } }; </code></pre> <p>You can use the classes like this:</p> <pre><code>MallardDuck md; SoundMaker sm; sm.makeSound(&amp;md); </code></pre> <p>Which outputs <code>Quack!</code>. Now lets add another derived class <code>RubberDuck</code>:</p> <pre><code>struct RubberDuck : public Duck { void squeak() const { std::cout &lt;&lt; "Squeak!" &lt;&lt; std::endl; } }; </code></pre> <p>If you want <code>SoundMaker</code> to use the class <code>RubberDuck</code> you must make changes in <code>makeSound</code>:</p> <pre><code>void makeSound(const Duck* d) { if (const MallardDuck* md = dynamic_cast&lt;const MallardDuck*&gt;(d)) { md-&gt;quack(); } else if (const RubberDuck* rd = dynamic_cast&lt;const RubberDuck*&gt;(d)) { rd-&gt;squeak(); } } </code></pre> <p>What if you need to add another type of duck and produce its sound? For every new type of duck you add, you will have to make changes in both the code of the new duck class and in <code>SoundMaker</code>. This is because you depend on concrete implementation. Wouldn't it be better if you could just add new ducks without having to change <code>SoundMaker</code>? Look at the following code:</p> <pre><code>struct Duck { virtual ~Duck() {} virtual void makeSound() const = 0; }; struct MallardDuck : public Duck { void makeSound() const override { quack(); } void quack() const { std::cout &lt;&lt; "Quack!" &lt;&lt; std::endl; } }; struct RubberDuck : public Duck { void makeSound() const override { squeak(); } void squeak() const { std::cout &lt;&lt; "Squeak!" &lt;&lt; std::endl; } }; struct SoundMaker { void makeSound(const Duck* d) { d-&gt;makeSound(); // No dynamic_cast, no dependencies on implementation. } }; </code></pre> <p>Now you can use both duck types in the same way as before:</p> <pre><code>MallardDuck md; RubberDuck rd; SoundMaker sm; sm.makeSound(&amp;md); sm.makeSound(&amp;rd); </code></pre> <p>And you can add as many duck types as you wish without having to change anything in <code>SoundMaker</code>. This is a <em>decoupled design</em> and is much easier to maintain. <em>This is the reason for why it is bad practise to down-cast and depend on concrete classes</em>, instead only use high-level interfaces (in the general case).</p> <p>In your second example you're using a separate class to evaluate if the requested behaviour of the derived class is available. This might be somewhat better as you separate (and <em>encapsulate</em>) the behaviour-control code. It still creates dependencies to your implementation though and every time the implementation changes you may need to change the behaviour-control code.</p>
    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. 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