Sunteți pe pagina 1din 3

Using C++ Objects in Tcl

Shyam Pather December 3, 1996

1 Introduction
Tcl was designed to be a exible, versatile scripting language, and as such, does not o er much in the way of structured coding mechanisms. In the absence of many structured programming elements, writing manageable Tcl code is rather di cult. Implementing the mechanisms needed to use objects (abstract data types consisting of both data, and the operations that can be performed on those data) in Tcl code, would go a long way to overcoming this problem. Since no direct method exists for creating objects using the standard set of Tcl commands, a more indirect approach is called for. This tutorial presents a way of creating and using objects using Tcl in conjunction with C++. It assumes some familiarity with object-oriented programming and C++.

2 Desired Functionality

In C++, one can de ne a class to which objects can belong. The class can have data members and member functions, known as methods. Objects of the class are referred to as instances of the class. Class methods can be invoked by prefacing their names with the name of an instance of the class, and data members can be referred to in the same way. These are the simplest constructs that enable object-oriented programming, and the goal of this tutorial shall be to implement these in Tcl.

3 Implementing the Desired Functionality


As described earlier, Tcl does not o er any direct means of implementing objects. Therefore, the approach used here involves a combination C++ and Tcl. The basic strategy is as follows: 1. De ne and implement a class in C++. 2. Implement (in C++) a Tcl command that will create new instances of the class. 3. Implement (in C++) a Tcl command that will provide access to each of the class member functions of a particular instance. 1

This tutorial uses a class called Counter to illustrate these techniques. The class is de ned in the le Counter.h, and implemented in the le Counter.cc. As the name suggests, instances of this class act as simple counters. They can be updated, reset, and queried for their current count. These operations are achieved through the class member functions Counter::Update(), Counter::Reset(), and Counter::GetCount() respectively. The Tcl interface to this class is implemented in the les CounterCmds.cc and CounterInit.cc. The Counter Init() function, implemented in CounterInit.cc, behaves much like a package initialization procedure (see \Creating New Tcl/Tk Commands Using C"). It simply registers a Tcl command called Counter. The purpose of this command is to create new instances of the Counter class, and thus achieves step 2 of the basic strategy outlined above. It takes one required argument, the name for the new instance, and one optional argument, a starting value for the counter. The Counter Tcl command is actually implemented by the C++ function CreateCounterObjectCmd() (CounterCmds.cc). This function creates a new instance of the class Counter using the C++ operator, new. It then registers the function CounterObjectCmd() as a Tcl command with the name the user passed as the rst argument to the Counter command. This then becomes the object command, and implements step 3 above. Each time the Counter Tcl command is invoked, CreateCounterObjectCmd() creates a new instance of the Counter class, and registers a new object command. Each object command is implemented by the function CounterObjectCmd and there is one object command for each instance of the class. The object command can therefore be viewed as a \handle" to the object. However, since each object has an object command that is implemented by the same C++ function, a method is needed for distinguishing one object command from another. This method involves the seldom-used clientData argument to the Tcl CreateCommand() function. Most calls to Tcl CreateCommand() pass a NULL pointer to the clientData argument. However, in this case, a pointer to the newly created instance of the Counter class is passed instead. When a command is registered, the clientData argument is saved and passed to the function that implements the command, whenever the command is executed. Thus, every time a counter object command is executed, CounterObjectCmd() is passed a pointer to the instance of the Counter class to which the object command refers. Although every object command is implemented by the same function (CounterObjectCmd()), this function gets called with a di erent clientData pointer for each one. It can then use this pointer to acces the appropriate instance of the Counter class. As described before, purpose of the object command is to give access to the member functions of the class. The rst argument to the object command is the name of the class method to invoke. CounterObjectCmd() checks the rst argument, and, using the pointer to the counter object given by the clientData argument, calls the appropriate member function. Another unusual aspect of the call to Tcl CreateCommand that registers the object command is the value of the deleteProc argument. The purpose of this argument is to provide a hook to a procedure to be called when the Tcl command being registered is eventually deleted. Very often, the value of this argument is NULL, resulting in the default deletion procedure being called. The standard deletion procedure will not su ce here, however, because the object command refers to a dynamically allocated object, which should be deleted 2

when the object command is deleted. To ensure this, we specify our own deletion procedure, namely DeleteCounter() which performs the appropriate actions.

4 Testing the implementation


The le CounterWish.c contains code for a wish-like interpreter that knows about the commands associated with our counter object. Running the Make le will result in an executable le, CounterWish that can be used to test the implementation. For example, typing Counter myctr will e ectively create a counter object called \myctr". Issuing myctr update will result in the member function \update" being called on the \myctr" object. Similarly, the other member functions can be invoked by prefacing the name of the function with the name of the object.

5 Concluding Remarks
The previous section, stated that typing Counter myctr would e ectively create an object named \myctr". In reality, a Tcl command named \myctr" is actually created, and this command provides access to the member functions of a C++ object created in the background. Thus the appearance of an object is achieved. The implementation described in this document provides an adequate mechanism for implementing the beginnings of an object-oriented Tcl environment. This approach certainly does not give full object-oriented capabilities, and other packages, such as incr Tcl, should be considered for applications requiring a more in-depth implementation.

S-ar putea să vă placă și