Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I think this statement reflects the confusion here (emphasis mine):</p> <blockquote> <p>I do not understand what specifically is required in a class to be eligible for being a base clas (<strong>not a polymorphic one</strong>)?</p> </blockquote> <p>In idiomatic C++, there are two uses for deriving from a class:</p> <ul> <li><strong>private</strong> inheritance, used for mixins and aspect oriented programming using templates.</li> <li><strong>public</strong> inheritance, used for <em>polymorphic situations only</em>. <strong>EDIT</strong>: Okay, I guess this could be used in a few mixin scenarios too -- such as <code>boost::iterator_facade</code> -- which show up when the <a href="http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern" rel="nofollow noreferrer">CRTP</a> is in use.</li> </ul> <p>There is absolutely no reason to publicly derive a class in C++ if you're not trying to do something polymorphic. The language comes with free functions as a standard feature of the language, and free functions are what you should be using here.</p> <p>Think of it this way -- do you really want to force clients of your code to convert to using some proprietary string class simply because you want to tack on a few methods? Because unlike in Java or C# (or most similar object oriented languages), when you derive a class in C++ most users of the base class need to know about that kind of a change. In Java/C#, classes are usually accessed through references, which are similar to C++'s pointers. Therefore, there's a level of indirection involved which decouples the clients of your class, allowing you to substitute a derived class without other clients knowing.</p> <p>However, in C++, classes are <strong>value types</strong> -- unlike in most other OO languages. The easiest way to see this is what's known as <a href="https://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c">the slicing problem</a>. Basically, consider:</p> <pre><code>int StringToNumber(std::string copyMeByValue) { std::istringstream converter(copyMeByValue); int result; if (converter &gt;&gt; result) { return result; } throw std::logic_error("That is not a number."); } </code></pre> <p>If you pass your own string to this method, the copy constructor for <code>std::string</code> will be called to make a copy, <strong>not the copy constructor for your derived object</strong> -- no matter what child class of <code>std::string</code> is passed. This can lead to inconsistency between your methods and anything attached to the string. The function <code>StringToNumber</code> cannot simply take whatever your derived object is and copy that, simply because your derived object probably has a different size than a <code>std::string</code> -- but this function was compiled to reserve only the space for a <code>std::string</code> in automatic storage. In Java and C# this is not a problem because the only thing like automatic storage involved are reference types, and the references are always the same size. Not so in C++.</p> <p>Long story short -- don't use inheritance to tack on methods in C++. That's not idiomatic and results in problems with the language. Use non-friend, non-member functions where possible, followed by composition. Don't use inheritance unless you're template metaprogramming or want polymorphic behavior. For more information, see Scott Meyers' <a href="http://rads.stackoverflow.com/amzn/click/0321334876" rel="nofollow noreferrer">Effective C++</a> Item 23: Prefer non-member non-friend functions to member functions.</p> <p>EDIT: Here's a more complete example showing the slicing problem. You can see it's output on <a href="http://codepad.org/72tZmoWx" rel="nofollow noreferrer">codepad.org</a></p> <pre><code>#include &lt;ostream&gt; #include &lt;iomanip&gt; struct Base { int aMemberForASize; Base() { std::cout &lt;&lt; "Constructing a base." &lt;&lt; std::endl; } Base(const Base&amp;) { std::cout &lt;&lt; "Copying a base." &lt;&lt; std::endl; } ~Base() { std::cout &lt;&lt; "Destroying a base." &lt;&lt; std::endl; } }; struct Derived : public Base { int aMemberThatMakesMeBiggerThanBase; Derived() { std::cout &lt;&lt; "Constructing a derived." &lt;&lt; std::endl; } Derived(const Derived&amp;) : Base() { std::cout &lt;&lt; "Copying a derived." &lt;&lt; std::endl; } ~Derived() { std::cout &lt;&lt; "Destroying a derived." &lt;&lt; std::endl; } }; int SomeThirdPartyMethod(Base /* SomeBase */) { return 42; } int main() { Derived derivedObject; { //Scope to show the copy behavior of copying a derived. Derived aCopy(derivedObject); } SomeThirdPartyMethod(derivedObject); } </code></pre>
 

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