The following is an example of how you can create instances of and extender (Labelling) for an object G belonging to Graph.
{ Graph G; // The graph Labelling L1(G); // This is a labelling for 'G' with automatic allocation Labelling* L2= new Labelling(G); // this is another labelling for 'G' using .... // dynamic allocation. .... // use 'L1' and 'L2' accessing their methods as usually .... delete L2; // A dynamic allocated object has to be deleted, as usual. Extension // objects deletion must be performed before support object deletion. .... // automatic deallocation of 'L1' is performed by C++ before automatic deallocation of 'G' // (see ANSI working paper) } |
You must remember to delete any dynamic extension before its support is deleted. Otherwise, deallocation of the support object provokes throwing an execption.
As you can see, the syntax for constructing and deleting extension objects is rather usual. There is only one remarkable thing: the constructor has at least one parameter (a reference or a pointer to the support).
If a Graph's subclass is declared in a dynamic hierarchy and you want to force a graph to belong to it, you must use static pseudo-constructors declared in such subclass. That call causes the creation of an extension object. A particular syntax is used to access the members in a dynamic hierarchy and to test if an object belongs to a subclass. All extension objects related to dynamic hierarchy are automatically deleted when its support is deleted. The user has to do nothing.
The following example shows the syntax (for the definition of ConnectedGraph and PlanarGraph see declaration of dynamic hierarchy):
main() { Graph g; // create an empty graph .... // various operations on 'g' // **** pseudo-consructors usage **** ConnectedGraph::Test(g); // 'g' could be recognized to be connectd PlanarGraph::Test(g); // 'g' could be recognized to be planar // **** membership test **** if (g.{ConnectedGraph}) // does 'g' belong to ConnectedGraph? { cout << "g is connected" << endl; g.{ConnectedGraph}.DFS_visit_all(v); // call a method of ConnectedGraph } if (g.{PlanarGraph}) // does 'g' belong to PlanarGraph? { cout << "g is planar" << endl; cout << "no. of faces=" << g.{PlanarGraph}.Get_number_of_faces() << endl; } // nothing to do before deletion of 'g' } |
In ECO C++ it is possible to attach extension objects to instances of classes declared as extensible.
The following is an example:
// // **** example of extesible class declaration **** // class Graph: extensible // this class can be support for extension objects { ... Vertex Add_New_Vertex(); // create a new vertex // E-methods declarations extend void Check_Add_New_Vertex() // check if adding a vertex is an operation compatible with current // extension-objects constraints, exeptions can be thrown extend void Pre_Add_New_Vertex() // execute all operations before real insertion extend void Post_Add_New_Vertex(Vertex v) // execute all operations after real insertion ... }; // // **** example of extender class declaration **** // class Labelling: extend Graph // this class is an extender of Graph { public: Labelling(Graph& g) {}; // constructor with 'g' compulsary parameter ~Labelling() {} // E-methods definitions void Check_Add_New_Vertex(); // do nothing: vertecies can be always added (no constraint on Graph) void Pre_Add_New_Vertex(); // do nothing void Post_Add_New_Vertex(Vertex v); // initialize with an empty label ... // convetional methods Set(Vertex, char*){} Get(Vertex); ... }; |
A special syntax makes easy to call E-methods inside Add_New_Vertex() definition.
In C++, objects cannot belong to more than one class. Also, it is impossible to change the type of one object at run-time. In ECO C++ it is possible to change the ECO type, using dynamic inheritance. The following is an example of declaration of a little dynamic hierarchy.
class Graph: extensible // class that can support extenders {...}; class ConnectedGraph: exensible dynamic Graph { private: ConnectedGraph( Graph& ) {}; // C++ constructor public: DFS_visit_all(Vertex v); // method avilable only for connected graph static void Test(Graph& g); // client class usable pseudo-constructor // if 'g' is a connected graph put 'g' in the class of // ConnectedGraph (according to ECO convention) providing // an extension-object for it. }; class PlanarGraph: exensible dynamic Graph { private: PlanarGraph( Graph& ) {...}; // C++ constructor ~PlanarGraph() {...}; // C++ destructor public: Get_number_of_faces(); // method avilable only for planar graph static void Test(Graph& g); // Pseudo-constructor usable by client class // It change the ECO type of 'g' calling the usual // C++ constructor. // If 'g' is a planar graph put 'g' in the class of // PlanarGraph providing an extension-object // for it. void Demote(); // Pseudo-destructor, demote the object calling the usual // C++ destructor. }; |
The keyword dynamic declare a subclass in a dynamic hierarchy. Usual C++ constructors (destructors) must be private and the user can force type promotion (demotion) by calling a pseudo-constructor (pseudo-destructor), if available. Pseudo-constructors are not compulsary and type promotion and demotion can be provoked also by ordinary methods or by methods of a friend class.
Promotion and demotion are performed by constructing and deleting an extension object that add new data and functionalities. The user can access such object using the syntax showed in usage of dynamic inheritance. Pseudo-constructors must be static member function because they cannot be member of an extension object that is not yet created! Pseudo-destructor can be ordinary member function.
If the clause extensible dynamic is used, the programmer can inherit a new dynamic subclass. C++ constructors with parameter "Graph&" are compulsory, whatever level of the hierarchy the class is in.