Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><em>Note: I'm not very familiar with Java.</em></p> <p>There's a major difference between "variables" in C++ and Java:</p> <pre><code>class X { public: int m = 5; }; X a; // no `= X();` required X b; a = b; a.m = 42; print(b.m); // this line is pseudo-code </code></pre> <p>In Java, variables may point to different objects. In the example above, after the assignment, <code>a</code> and <code>b</code> point to the same object. Modifying this object through one will make the modification visible when accessing the object through the other, <code>print(b.m)</code> will print <code>42</code>.</p> <p>In C++, "variables" (actually: <em>names</em>) always refer to the same object. There are two objects, one named <code>a</code> and one named <code>b</code>, and the assignment doesn't change that. Per default/convention, assignment in C++ means (deep) copy. <code>a = b</code> will be interpreted by most people and in the case of built-in types as <em>copy the contents of <code>b</code> to <code>a</code></em> (or, more formally, <em>change <code>a</code> such that it will be equal to <code>b</code> afterwards, without altering <code>b</code></em>).</p> <p>Now it should be clear that you cannot alter which override of <code>worked</code> will be called by using the assignment in C++: which override of a virtual function is called is selected based on the type of the object (dynamic type), and you cannot change which object a name (variable) refers to.</p> <hr> <p>However, there are pointers in C++, so-called <em>raw pointers</em> and <em>smart pointers</em>. Pointers are objects themselves that point to other objects of one specific type. <code>X*</code> is a raw pointer that points to an object of type <code>X</code> <sub>even with polymorphism!</sub> Similarly, <code>std::shared_ptr&lt;X&gt;</code> is a smart pointer that points to an object of type <code>X</code>.</p> <pre><code>std::shared_ptr&lt;X&gt; pa = std::make_shared&lt;X&gt;(); std::shared_ptr&lt;X&gt; pb = std::make_shared&lt;X&gt;(); </code></pre> <p>Every <code>make_shared</code> creates an object. So we have four objects in this example: <code>pa</code>, <code>pb</code>, and the two unnamed objects created via <code>make_shared</code>.</p> <p>For pointers, there are several operators for dealing with the object pointed to. The most important one is the asterisk, which <em>dereferences</em> the pointer. <code>*pa</code> will give you the object <code>pa</code> points to. The <code>pa-&gt;</code> operator is a shorthand for <code>(*pa).</code>, so you can use it to access members of the object pointed to. The assignment of pointers <em>does not copy the object pointed to</em>. After the assigment <code>pa = pb</code>, both will point to the <em>same object</em>. For smart pointers, that implies cleaning up objects that are not referred to any more:</p> <pre><code>std::shared_ptr&lt;X&gt; pa = std::make_shared&lt;X&gt;(); std::shared_ptr&lt;X&gt; pb = std::make_shared&lt;X&gt;(); // 4 objects exist at this point pa = pb; // only 3 objects still exist, the one `pa` formerly pointed to was destroyed </code></pre> <hr> <p>Polymorphism in C++ now works with either references (not explained here) or pointers. I said earlier that pointers can only point to one specific type of object. The crux is that this object might be part of a bigger object, e.g. via composition. But inheritance in C++ is very similar to composition: all the members of a base class become part of the <em>base class subobject</em> of a derived class' object:</p> <pre><code>std::shared_ptr&lt;Obj1&gt; pobj1 = std::make_shared&lt;Obj1&gt;(); std::shared_ptr&lt;Obj&gt; pobj = pobj1; </code></pre> <p>Here, <code>pobj</code> points to the <em><code>Obj</code> base class subobject</em> within the object <code>*pobj1</code> (i.e. within the object <code>pobj1</code> points to).</p> <p>Polymorphism now works via virtual functions. Those have a special rule for which function is actually called. The expression <code>*pobj</code> gives us the object which <code>pobj</code> points to, and it is of type <code>Obj</code>. But in this example, it is only a <em>base class subobject</em>, i.e. the object we originally created is of a type derived from <code>Obj</code>. For these cases, we differentiate between the <em>static</em> and the <em>dynamic type</em> of an expression:</p> <ul> <li>The static type of <code>*pobj</code> is always <code>Obj</code> - generally, for an object <code>p</code>, whose type is <em>pointer to <code>some_type</code></em>, the static type of <code>*p</code> is just <code>some_type</code>, removing one level of indirection / one <em>pointer to</em>.</li> <li>The dynamic type of <code>*pobj</code> depends on which object <code>pobj</code> currently points to, and therefore generally is not known at compile-time. If the object is a <em>base class subobject</em>, we use the <em>derived class object</em> which it is part of, and recurse until the object we have is not a <em>base class subobject</em> any more. The type of the object we end up with is the dynamic type of the expression. In the example above, <code>pobj</code> points to the <em><code>Obj</code> base class subobject</em> of <code>*pobj1</code>. The object <code>*pobj1</code> itself is not a <em>base class subobject</em> here, therefore the dynamic type of <code>*pobj</code> is <code>Obj1</code>.</li> </ul> <p>This dynamic type is now used to select which virtual function override is called. In the case <code>pobj-&gt;worked()</code>, where the dynamic type of <code>*pobj</code> is <code>Obj1</code>, the override selected is <code>Obj1::worked</code>, which will return true.</p> <p>N.B. As <a href="https://stackoverflow.com/users/103167/ben-voigt">Ben Voigt</a> pointed out, the dynamic type does not depend on composition. It is only about inheritance.</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. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      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