Next: Thread-safe Shell, Previous: Integrating C++ Code, Up: Code Integration [Contents][Index]
We already saw how to connect code directly to event slots in the
interface. If we desire to encapsulate this code, we can use a
component without a behavior8 to achieve this. The code generator will
generate a similar C++ representation for components with and without
behavior. The only difference is that a component without behavior
declares pure virtual functions which must be implemented by a struct of
class which inherits from the generated C++ representation. Note that
this approach is not suitable to wrap a Dezyne component or system,
since it would add the Dezyne semantic constraints via the runtime
library a second time. The derived struct or class must have the same
name as the component in Dezyne. To avoid a naming conflict, the
generated representation with the same name as the Dezyne component is
placed into the skel
9
namespace.
It may not be obvious that we may run into a conflict when we put our
foreign component in a file with the same name as the component. The
reasons for this are as follows. Names introduced in Dezyne are also
used by the generated code to refer to component representations. If a
component is not defined locally Dezyne import is mapped to a
#include
. This means that the actual implementation of a foreign
component must be in a file with the name derived from the component
name. Therefore the component representation in the skel
namespace is not written to the same file, the code generator simply
refuses this. The solution is to put foreign component definitions into
another file, for instance in the file of the system instantiating the
component.
When implementing the foreign component the compiler must also be able
to see the representation in the skel
namespace. The code
generator makes sure that the actual implementation inheriting the
skel
representation is included directly after it. Therefore we
do not have to include anything into the header file of our foreign
implementation. However, if we put the actual definition into a
separate source file, we must include both the header file of the actual
foreign component as well as the header file declaring the skel
representation.
An example will help clarifying:
// hello_foreign.dzn interface ihello { in void hello (); out void world (); behavior { on hello: world; } } component foreign { provides ihello p; } component hello { provides ihello p; requires ihello r; behavior { on p.hello (): r.hello (); on r.world (): p.world (); } } component hello_foreign { provides ihello p; system { p <=> h.p; hello h; h.r <=> f.p; foreign f; } } // end of hello_foreign.dzn
Here we see an interface ihello
, a foreign
component, a
regular component hello
and a system hello_foreign
being
defined.
For C++ the code generator produces a hello_foreign.hh and a
hello_foreign.cc file. Since hello_foreign
instantiates
the component foreign
, it will #include
a file called
foreign.hh. The contents of this file might look something like
this:
#ifndef FOREIGN_HH #define FOREIGN_HH struct foreign: public skel::foreign { foreign (const dzn::locator &locator) : skel::foreign (locator) {} void p_hello () { p.out.world (); } }; #endif
Note the absence of an #include
statement.
If we want to move all member function definitions from the header file to a source file, we might write foreign.cc like this.
#include "hello_foreign.hh" foreign::foreign (const dzn::locator &locator) : skel::foreign (locator) {} void foreign::p_hello () { p.out.world (); }
Note the presence of #include "hello_foreign.hh"
and remember
this already includes foreign.hh.
A foreign component is a component without behavior in Dezyne.
skel
is short for skeleton.
Next: Thread-safe Shell, Previous: Integrating C++ Code, Up: Code Integration [Contents][Index]