View on GitHub

Cpptcl

C++/Tcl, a library that allows to easily integrate C++ and Tcl.

Download this project as a .zip file Download this project as a tar.gz file
[prev][top][next]

Exposing Classes

Exposing classes is a little bit more involving, since there is more than name that needs to be defined.
Let's suppose that we have the following C++ class:

class Person {
public:
  void setName(string const &n) { name = n; }
  string getName() { return name; }

private:
  string name;
};

We can expose this class in some extension (or to the embedded interpreter) like this:

CPPTCL_MODULE(Mymodule, i) {
  i.class_<Person>("Person")
    .def("setName", &Person::setName);
    .def("getName", &Person::getName);
}

Note: The i parameter to the CPPTCL_MODULE macro is a name that you later use to refer to the interpreter. You can choose whatever name you like. The rest of the code is the same as if the following object was declared in the C++ program:

interpreter i;

Anyway - as you see, the class is defined using the class_ member function template, called on the interpreter object (it could not be named "class", since that is a keyword in C++).
The string name that is provided as a parameter to the class_ function is a name that will be visible to the Tcl scripts - again, it does not have to be the name of the C++ class that you use in code.

Member functions

This special class_ function returns an object that can be used to define class member functions, in the same expression and in a chained way.
The above example is written in three lines just to make it more readable, but it is a single C++ instruction:

i.class_<Person>("Person").def("setName", &Person::setName).def("getName", &Person::getName);

The rules for defining class member functions are the same as the rules used for Exposing Free Functions.

After the class is exposed, it can be used in the following way (let's suppose that the above was compiled to the shared library named mymodule.so):

% load ./mymodule.so
% set p [Person]
p0x807b790
% $p setName "Maciej"
% $p getName
Maciej
%

As you see, there is a Person command that creates and returns a new object. This is simply a constructor of our class. It returns a name of the new object (here it is p0x807b790 - it may be different on your machine or when you run the same program twice; you should not attach any external meaning to this name) and this name is immediately available as a new command, to use with member functions.
For example, the expression:

% $p setName "Maciej"

calls the member function setName with the parameter "Maciej", on the object whose name is stored in the variable p.
Later, the expression:

% $p getName

calls the member function getName without any parameters and it returns the string result of that call.

Constructors

In the above example, the class Person has no constructors. Or, to be strict, it has a default constructor without parameters.
The Person class could be exposed also in the following way:

i.class_<Person>("Person", init<>())
  .def("setName", &Person::setName)
  .def("getName", &Person::getName);

As you see, there is a special init object provided. It can carry information about the expected parameters that are needed for constructor, as in the following full example:

// example4.cc
#include "cpptcl.h"
#include 

using namespace std;
using namespace Tcl;

class Person {
public:
  Person(string const &n) : name(n) {}

  void setName(string const &n) { name = n; }
  string getName() { return name; }

private:
  string name;
};

CPPTCL_MODULE(Mymodule, i) {
  i.class_<Person>("Person", init<string const &>())
    .def("setName", &Person::setName)
    .def("getName", &Person::getName);
}

The init object can bring with it information about the number and the types of parameters needed by the constructor.
Above, it declares that the constructor of class Person needs 1 parameter of type string const &.
This means that we cannot use this exposed class from the Tcl script the same way as before:

% set p [Person]
Too few arguments.
% 

Instead, we have to provide required parameters:

% set p [Person "Maciej"]
p0x807b7c0
% $p getName
Maciej
%

Constructors with up to 9 parameters can be defined this way.

Another form that may be sometimes useful is:

i.class_<Person>("Person", no_init)
    .def("setName", &Person::setName);
    .def("getName", &Person::getName);

This basically means that the exposed class has no constructors at all (or, to be strict, we do not want them to be visible from Tcl).
Objects of such classes need to be created by separate factory functions.

Destructors

There is additional "member function" that is automatically defined for each class, which is used for destroying the object:

% $p -delete

Once this is done, the object itself is destroyed and the associated command is removed from the interpreter.
This means that the name stored in the variable p cannot be used for executing member functions any more:

% $p getName
invalid command name "p0x807b790"
%