set tcp1 [new Agent/TCP/Reno] |
Agent/TCP/Reno (BTW, slashes "/" are considered as ordinary characters in OTcl) is the name of an existing class in the OTcl language interpreter
(Now the ordinary OTcl language interpreter does not have this class, the people who made NS expanded OTcl to include this class)
Method outline:
|
By "a new Agent" class, I mean a class that inherits from the NS Agent class
(Afterall, C++ is an Object Oriented programming language and you can save a lot of programming work by inheriting from the proper class that is already defined in NS)
Nope, in fact, the MyAgent class is kinda dumb and has only 2 methods that print some internal variables.
(A new super-duper TCP protocol agent will make things so messy that you may not understand how things work between C++ and OTcl).
// *********************** // Include files... // *********************** #include <stdio.h> #include <string.h> #include "agent.h" // The MyAgent class is a subclass of Agent // So we need to include the definition of "Agent" |
static class MyAgentClass : public TclClass { public: /* ----------------------------------------------------------- Constructor Invokes the constructor of the parent class (TclClass) The method TclClass registers the name "Agent/MyAgentOtcl" as a newly supported OTcl class ----------------------------------------------------------- */ MyAgentClass() : TclClass("Agent/MyAgentOtcl") {} } |
NOTE:
Static classes in C++ are classes that do not contain instance members (other than those inherited from the class Object) and do not have a callable constructor. |
So we can explicitly define class hierarchies in OTcl using a pathname syntax.
Example:
|
(Note: in C++, only virtual methods in a class can be overriden by a method in the subclass)
new Agent/MyAgentClass |
the OTcl interpreter will invoke the method create(int argc, char **argv) in the TclClass class (because we used the string "Agent/MyAgentClass" as argument in TclClass("Agent/MyAgentOtcl") )
OTcl can now use this pointer to invoke the command() method (the main entry point for all OTcl objects).
static class MyAgentClass : public TclClass { public: /* ----------------------------------------------------------- Constructor Invokes the constructor of the parent class (TclClass) The method TclClass registers the name "Agent/MyAgentOtcl" as a newly supported OTcl class ----------------------------------------------------------- */ MyAgentClass() : TclClass("Agent/MyAgentOtcl") {} /* ----------------------------------------------------------- Overridden create(argc, argv): This method is invoked by OTcl interpreter when [new Agent/MyAgentOtcl] is executed We must override the inheritted method and create our MyAgent object !!! ----------------------------------------------------------- */ TclObject* create(int argc, const char*const* argv) { return(new MyAgent()); } } |
Make C++ execute the code :
MyAgentClass() : TclClass("Agent/MyAgentOtcl") { } |
ONCE
static class MyAgentClass : public TclClass { public: /* ----------------------------------------------------------- Constructor Invokes the constructor of the parent class (TclClass) The method TclClass registers the name "Agent/MyAgentOtcl" as a newly supported OTcl class ----------------------------------------------------------- */ MyAgentClass() : TclClass("Agent/MyAgentOtcl") {} /* ----------------------------------------------------------- create(argc, argv): Method is invoked by OTcl interpreter when [new Agent/MyAgentOtcl] is executed We must take care of creating the actual MyAgent object ourselves ----------------------------------------------------------- */ TclObject* create(int argc, const char*const* argv) { return(new MyAgent()); } } MyAgentClass dummy; // Dummy variable definition // This variable is not used anywhere // The purpose is to force OTcl interpreter to // execute the constructor in MyAgentClass ONCE |
static class MyAgentClass : public TclClass { public: /* ----------------------------------------------------------- Constructor Invokes the constructor of the parent class (TclClass) The method TclClass registers the name "Agent/MyAgentOtcl" as a newly supported OTcl class ----------------------------------------------------------- */ MyAgentClass() : TclClass("Agent/MyAgentOtcl") {} /* ----------------------------------------------------------- create(argc, argv): Method is invoked by OTcl interpreter when [new Agent/MyAgentOtcl] is executed We must take care of creating the actual MyAgent object ourselves ----------------------------------------------------------- */ TclObject* create(int argc, const char*const* argv) { return(new MyAgent()); } } MyAgentClass dummy; |
set x [new Agent/MyAgentOtcl] |
The OTcl command "[new Agent/MyAgentOtcl]" triggers OTcl to invoke the "create(0, null)" (because there is no further arguments in [new Agent/MyAgentOtcl]) in the "MyAgentClass".
This in turn, invokes "new MyAgent()" and returns an MyAgent object and asigned to the OTcl variable x.
Examples:
$x set my_var1_otcl 2 $x set my_var2_otcl 3.14 |
$x call-my-priv-func $x showvars |
When OTcl executes:
$x s1 s2 s3 ... |
The OTcl interpreter will execute the method:
command( argc, argv ) with: argv[0] = "x" argv[1] = "s1" argv[2] = "s2" argv[3] = "s3" ... |
Look at the implementation of the command() function ( click here ) and you will see that:
I stored it in:
OBJ_CC = \ 01-MyAgent/MyAgent.o \ ... |
You can see the modified Makefile: click here
File ns-default.tcl: Agent/MyAgentOtcl set my_var1_otcl 0 Agent/MyAgentOtcl set my_var2_otcl 0 |