我正在用C ++代码扩展Itcl程序,但是出现了以下问题。
我想使用TCL-C API将Itcl代码中的“引用”返回到C ++代码中的对象,返回值应注册到Itcl代码中的对象,因此在此之后,我可以调用它的方法。 我的问题是我真的不知道双方该如何做。
我看到,使用TCL_LINKVAR(...)API函数,我可以在此对象之间创建到TCL中的字符串的链接,但是我真的不了解如何使用TCL_LINKVAR函数来处理对象而不是原始对象类型,例如int,double等...
我将举一个小例子: 这是我的C ++代码:
Tcl-C API代码
#include <tcl.h>
#include "classA.h"
class MyObject {
int id;
ClassA * a; // classA is defined somewhere else
public:
MyObject(int iid) : id(iid) {}
void returnA() { return a; }
};
extern "C" int do_something_command(ClientData clientData,
Tcl_Interp* interp,
int objc,
Tcl_Obj* const objv[])
{
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "method ?argument ...?");
return TCL_ERROR;
}
MyObject* p = (MyObject*)clientData;
classA * ret_val = p->returnA();
if (LINK_VAR.... != TCL_OK) { // here should be a linkage between ret_val to an Itcl object
return TCL_ERROR;
}
return TCL_OK;
}
extern "C" int test_create(ClientData clientData,
Tcl_Interp* interp,
int objc,
Tcl_Obj* const objv[])
{
static int obj_count = 0;
MyObject* p = new MyObject(obj_count);
char obj_name[13 + TCL_INTEGER_SPACE];
sprintf(obj_name, "::testobj%d", obj_count++);
Tcl_CreateObjCommand(interp, "cDoSomething",
(Tcl_ObjCmdProc*)do_something_command,
(ClientData) p, (Tcl_CmdDeleteProc *) NULL);
Tcl_SetObjResult(interp, Tcl_NewStringObj(obj_name, strlen(obj_name)));
return TCL_OK;
}
extern "C" DLLEXPORT int Test_Init(Tcl_Interp *interp)
{
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
if (Tcl_PkgProvide(interp, "test", "0.1") != TCL_OK) {
return TCL_ERROR;
}
Tcl_CreateObjCommand(interp, "test::create",
(Tcl_ObjCmdProc*)test_create,
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
return TCL_OK;
}
Itcl代码
load test.o // this will be the name of .o file I will create from my C++ code
itcl::class A {
...
public method doSomething {}
... }
itcl::class B {
constructor {} {
set temp [test::create]
set a [$temp cDoSomething] // should register a as an classA object
// here I will call methods that are related to classA object that are registered in C++
}
...
}
答案 0 :(得分:2)
首先,简单 C类型(仅数字和char*
(其中Tcl管理char*
的内存分配)和Tcl变量之间的变量链接映射;它并不真正适合您的工作。原则上,您可以对任何结构执行相同操作;链接代码是对基本Tcl变量跟踪原始API的包装。它实际上不适用于任何不透明类型或具有动态生命周期的任何内容。
最简单的技术是在C ++端保留映射(例如std::map<std::string,MyObject*>
),以便您可以进行按名称查找操作。一旦了解了这一点,就可以发明一种简单的命名机制,并将字符串名称保留在Itcl对象的Tcl变量中。 C ++端的方法由以下命令代理,这些命令将名称作为参数之一,查找相关对象,然后将其余参数传递给您(使用您喜欢的任何其他解析/类型转换),以及Itcl方法是琐碎的包装程序,它们在正确的位置传递了其他名称/句柄(析构函数是相同的,只不过它代表从地图中移除和delete
的代理)。还有其他方法可以做到这一点,但是我刚刚描述的方法很容易实现,并且应该首先尝试做。它使您无需在设计级别花费大量精力即可对API进行原型设计。请注意,对象不要的字段以这种方式很好地映射。它仅用于方法,而在C ++中生成良好API的原因与在Tcl / Itcl中生成良好API的原因绝对不相同。
您可以通过使用SWIG生成绑定来实现相似的目的。它在内部所做的操作并没有太大不同,但是它在C ++中的绑定比Tcl方面的更多。 Itcl包装的工作方式会有所不同……
如果您使用的是Itcl 4,则可以使用TclOO API(在Itcl 4的基础上构建)从C ++完成方法绑定。 TclOO包括用于定义自定义方法以及将C和C ++对象直接附加到其实例的机制。这可以使绑定变得更加复杂(并使您可以执行诸如Tcl方面的子类化之类的事情),但由于这个原因,它变得更加复杂。而且,您最终将获得的API至少从外观上类似于我上面概述的外观。