Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>After some experimenting I have concluded that the general design cannot be changed to be 100% type-safe. However, there are some situations where you can help ensure that the offended method is only called with the correct sub-type.</p> <p>Taking the graph example, what we need to do is to insure that a sub-class of <b>GraphVertex</b> (in this case <b>AMGVertex</b>) only can access the related sub-class of <b>Graph</b> (that is for <b>AMGVertex</b>, class <b>AdjacencyMatrixGraph</b>). Hence insuring that the correct type is inserted at the <b>removeVertex(GraphVertex *v)</b> method. To do this, a non-public visibility can be used for methods that are accessed by the abstract class <b>GraphVertex</b>. Also the visibility of the constructors of all the sub-types of <b>GraphVertex</b> must be non-public. Of course the constructor of <b>AMGVertex</b> must be visible from <b>AdjacencyMatrixGraph</b> and the <b>removeVertex</b> must be visible from <b>AMGVertex</b>. In C++ this can be done with <i>friends</i>.</p> <pre><code>template&lt;class T&gt; class GraphVertex { public: virtual ~GraphVertex() {} void remove() { m_graph.removeVertex(this); } protected: GraphVertex(Graph&lt;T&gt; &amp;graph) : m_graph(graph) {} Graph&lt;T&gt; &amp;m_graph; } template&lt;class T&gt; class Graph { friend class GraphVertex&lt;T&gt;; public: virtual GraphVertex&lt;T&gt; add(T value) = 0; protected: // Or private? virtual void removeVertex(GraphVertex&lt;T&gt; *v) = 0; } template&lt;class T&gt; class AMGVertex : public GraphVertex&lt;T&gt; { friend class AdjacencyMatrixGraph&lt;T&gt;; protected: // Or private? AMGVertex(AdjacencyMatrixGraph&lt;T&gt; &amp;graph) : GraphVertex&lt;T&gt;(graph) {} } template&lt;class T&gt; class AdjacencyMatrixGraph : public Graph&lt;T&gt; { public: AMGVertex *add(T value) { ... } // Calls AMGVertex's constructor. protected: // Or private? void removeVertex(GraphVertex&lt;T&gt; *v) // Only visible from this class and through base class. { ... } } </code></pre> <p>So, <b>AMGVertex</b> can only be created from <b>AdjacencyMatrixGraph</b>, and hence a call to <b>AMGVertex::remove()</b> will always call <b>AdjacencyMatrixGraph::removeVertex(GraphVertex *v)</b> with the correct sub-class as parameter.</p> <p>It is however still possible to circumvent this, simply by creating a new vertex type with a <b>AdjacencyMatrixGraph</b> as <b>m_graph</b>. This is because the <i>friendship</i> from vertex to graph is in the abstract base-class.</p> <p>So a 100% type-safe solution is (at least from what I've gathered) not possible.</p> <p>In Java I believe similar results can be achieved with nested classes (to overcome visibility limitations).</p> <p>Thank you for the replies! If someone has a better solution, let us know. </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