5 Examples
5.1 A first example
This first simple example of the use of the europa standard just builds a class that prints out the name of each public member called. It also uses an object (of type Colour
) which represents some allocation strategy for the reified object; it simulates some mapping strategy, e.g. in the case of the creation of a remote object.
The first thing is to declare a reified class, inheriting from EC_Reflect
; the user will just inherit from that class in order to get the desired behaviour.
namespace EC { class Echo: public EC_Reflect { public: void* operator new (size_t s, Colour m); protected: Echo_P* ec_proxy(); } ; }
The Echo_P
class, a proxy class, implements the printing behaviour. The allocator new allows for passing the mapping parameter. Now, all classes that will inherit from Echo
will be automatically given the corresponding proxy, and as such, its behaviour.
The second thing to define, as a library programmer, is the proxy class that implements the behaviour:
namespace EC { class Echo_P : public EC_Proxy { public: EC_Any obj; // Reified object Colour mapping; // Some allocation or mapping value void ec_reify (EC_Call* c) { cout << c->mb->name() << endl; // print out the name c->res=c->execute(obj); // do the call } // Constructor Echo_P (Colour m, EC_Class cl, EC_Call* c) { mapping = m; obj = cl.new_obj(c); // Create the reified object } } ; }
The class holds a reference to the object for which it acts as a proxy (obj
). The attribute mapping (type Colour) holds the mapping value. The routine ec_reify
programs the desired behaviour:
Finally, the constructor routine receives as a first parameter the allocator parameter (of type Colour
, not really used in that example), and then the type of the actual object being created (EC_Call
), and the reification of the constructor (EC_Class
). The routine just creates the object, and assigns it to the obj
attribute of the proxy in order to keep a reference to it.
Let us say we have a typical user class of the form:
class C { // Any user class public: Res* foo ( param ); virtual Res* vfoo ( param ); // Constructors C(P1 pl); C(P1 p2); }
If a final user needs to add the echo behaviour to this class, he will only need to declare the following:
class Cecho : public C, public Echo { public: Cecho(P1 pl): C(pl) Cecho(P1 p2): C(p2) }:
Then the class Cecho can be used directly:
void main() { P1 pl; Colour green; Cecho* ce = ec_new ((green), Cecho, (pl)); r = ce->vfoo(...); r = ce->foo (...); }
Both functions will present the echo behaviour. If one needs to use the Cecho
class in an existing application, it can be done through polymorphism between entities of type C
and Cecho
:
void main() { P1 pl; Colour green; C* c; Cecho* ce = ec_new ((green), Cecho, (pl)); c = ce; // Polymorphic assignment r = c->vfoo(...); }
Of course in this case, due to the dynamic binding that occurs only on virtual functions in C++, the echo behaviour will occur only on those functions declared virtual in C
.
Copyright © 1997 EUROPA WG
Last updated: 26 Nov 1997