3.5.1 How to Bind Static C++ Class Member Variables

In Section 3.4, we have seen how to expose member variables of a C++ object into OTcl space. This, however, does not apply to static member variables of a C++ class. Of course, one may create an OTcl variable for the static member variable of every C++ object; obviously this defeats the whole meaning of static members.

We cannot solve this binding problem using a similar solution as binding in TclObject, which is based on InstVar, because InstVars in TclCL require the presence of a TclObject. However, we can create a method of the corresponding TclClass and access static members of a C++ class through the methods of its corresponding TclClass. The procedure is as follows:

  1. Create your own derived TclClass as described above;
  2. Declare methods []bind and []method in your derived class;
  3. Create your binding methods in the implementation of your []bind with add_method("your_method"), then implement the handler in []method in a similar way as you would do in []TclObject::command. Notice that the number of arguments passed to []TclClass::method are different from those passed to []TclObject::command. The former has two more arguments in the front.

As an example, we show a simplified version of PacketHeaderClass in ~ns/packet.cc. Suppose we have the following class Packet which has a static variable hdrlen_ that we want to access from OTcl:

class Packet {
        ......
        static int hdrlen_;
};
Then we do the following to construct an accessor for this variable:
class PacketHeaderClass : public TclClass {
protected:
        PacketHeaderClass(const char* classname, int hdrsize);
        TclObject* create(int argc, const char*const* argv);
        /* These two implements OTcl class access methods /
        virtual void bind();
        virtual int method(int argc, const char*const* argv);
};

void PacketHeaderClass::bind()
{
        /* Call to base class bind() must precede add_method() /
        TclClass::bind();
        add_method("hdrlen");
}

int PacketHeaderClass::method(int ac, const char*const* av)
{
        Tcl& tcl = Tcl::instance();
        \* Notice this argument translation; we can then handle them \
as if in TclObject::command() */
        int argc = ac - 2;
        const char*const* argv = av + 2;
        if (argc == 2) {
                if (strcmp(argv[1], "hdrlen") == 0) {
                        tcl.resultf("%d", Packet::hdrlen_);
                        return (TCL_OK);
                }
        } else if (argc == 3) {
                if (strcmp(argv[1], "hdrlen") == 0) {
                        Packet::hdrlen_ = atoi(argv[2]);
                        return (TCL_OK);
                }
        }
        return TclClass::method(ac, av);
}
After this, we can then use the following OTcl command to access and change values of Packet::hdrlen_:
        PacketHeader hdrlen 120
        set i [PacketHeader hdrlen]

Tom Henderson 2011-11-05