我需要在C ++中实现一个类 QoreFoo ,并通过.qpp实现Qore脚本 Foo 的双重实现。 QoreFoo是提供通用API的抽象类,实体功能将在后代和类中添加(在C ++或Qore中)。无论在何处使用后代类,都需要将来自核心(即C ++)的Foo API调用传播到实例化对象。
QoreFoo.h
# implement general API
class QoreFoo {
public:
virtual void bar(ExceptionSink *xsink)=0;
};
extern QoreFoo* current_foo;
// just assign instance of a descendant of QoreFoo
void QoreAssignFoo(QoreFoo* n_foo) {
current_foo = n_foo;
}
QoreFoo.cpp
QoreFoo* current_foo = 0;
any.cpp
if (current_foo)
current_foo.bar(xsink); // propagate call via overriden method
当我需要实现C ++后代时,这是微不足道的:
QoreFoo2.h
class QoreFoo2: QoreFoo {
void bar(ExceptionSink *xsink) {
# my stuff
printf("Hello World from C++");
}
};
usage.cpp
QoreAssignFoo(new QoreFoo2);
# wait for "Hello World from C++" when core calls current_foo.bar()
.....
但是怎么做才能传播对Qore脚本类的调用?我认为需要一个额外的类来调用.qpp中定义的双重类并重写.q
QoreFooHelper.h
class QoreFooHelper: class QoreFoo {
private:
QoreObject* qo;
public:
QoreFooHelper(QoreObject* n_qo): qo(n_qo) {
}
void bar(ExceptionSink *xsink) {
// convert args if any
// call virtual function of Foo class, i.e. qo
qo->evalMethod("bar", 0, xsink);
}
QC_Foo.qpp
# implement assign instance function
nothing assignFoo(*Foo foo) {
QoreAssignFoo(foo->p);
}
#implement class for Qore script
qclass Foo [arg=QoreFooHelper* p]
Foo::constructor() {
assert(self->validInstanceOf(CID_FOO)); // is it correct test to test if inherited from ?
QoreFoo* f = new QoreFooHelper(self);
self->setPrivate(CID_FOO, f);
}
# probably useless as it generates function code
#nothing Foo::bar() {
#}
Test.q
class Foo2 inherits Foo {
nothing bar() {
# my stuff
printf("Hello world from Q");
}
}
Foo2 foo();
assignFoo(foo); # assign instance of Foo2
# wait for "Hello World from Q" message when core calls current_foo.bar()
....
这是可行的解决方案,还是确实存在更好的方法,例如使用qpp功能或避免使用 QoreFooHelper (但在C ++中完全实现 QoreFoo2 时我需要避免开销)?
如果没有那么什么是替代选项,例如以某种方式传递callref或闭包并进行真正的回调?
修改
在.qpp中定义Qore类时, qpp 生成类定义 QoreClass * initFoo()(添加方法,构造函数等)并将其注册到命名空间存储库中
当要创建新的 QoreObject 时,将使用 QoreClass 作为命名空间repo中的参数构建。
.qpp定义的构造函数通常创建纯C ++ QoreFoo 实例并指定为私有属性( self-> setPrivate(CID_FOO,new QoreFoo())),即链接从 Foo 到 QoreFoo 已建立并将在定义.qpp方法时使用,其中使用纯C ++操作。 .qpp在函数" header"中生成了适当的C ++代码。 self 是 QoreObject 实例。
我认为在 Foo3 脚本类的运行时也是如此。
Qpp帮助实现Qore的东西来调用C ++的东西。
但我需要相反的方向,从C ++调用Qore方法,所以我想我需要调用 QoreObject :: evalMethod()。正如QoreObject没有 存在于普通的C ++类中,因此需要额外的后代 QoreFooHelper 来实现它(在将常规对象作为参数传递时会出现额外的问题)。
答案 0 :(得分:3)
如果要强制执行的API是Qore语言类API,则需要在Qore中实现抽象类,而不是在C ++中实现。
如果你有一个应该在Qore中扩展的C ++虚拟类层次结构,那么你应该使用qpp在C ++中实现你的Qore类,然后允许程序员通过在Qore中对你的类进行子类化来自然地扩展它。
你可以这样做:
QoreFoo.h
class QoreFoo {
public:
DLLLOCAL QoreFoo(QoreObject* o) : obj(o) {
}
// other functions...
private:
QoreObject* obj; //!< The QoreObject this private data is associated with
};
QC_Foo.qpp
//! This class defines an abstract interface for ...
/**
*/
qclass Foo [arg=QoreFoo* foo; ns=Foo];
//! Constructor
/** Used by subclasses defined in Qore
*/
Foo::constructor() {
self->setPrivate(CID_FOO, new QoreFoo(self));
}
//! a method to ...
/**
*/
abstract nothing Foo::bar();
这允许类Foo
拥有一些私有数据和一个可供子类使用的抽象Qore API; C ++中的子类(使用qpp实现)应将Foo
声明为vparent
,如下例所示:
QoreFoo2.h
#include "qore/intern/QoreFoo.h"
class QoreFoo2 : public QoreFoo {
public:
DLLLOCAL QoreFoo2(QoreObject* o) : QoreFoo(o) {
}
DLLLOCAL void bar(ExceptionSink* xsink) {
printf("Hello World from C++");
}
// other functions...
};
QC_Foo2.qpp
#include "qore/intern/QoreFoo2.h"
//! This class ...
/**
*/
qclass Foo2 [arg=QoreFoo2* foo; ns=Foo; vparent=Foo];
//! Constructor
/** Used by subclasses defined in the Qore programming language.
*/
Foo2::constructor() {
self->setPrivate(CID_FOO2, new QoreFoo2(self));
}
//! a method to ...
/**
*/
nothing Foo2::bar() {
foo->bar();
}
此外,Foo
类可以以相同的方式直接在Qore中进行子类化:
class Foo3 inherits Foo {
bar() {
print("Hello world from Q");
}
}
修改强>
@TMa如果你想从C ++调用Qore语言方法,然后如前所述使用QoreObject::evalMethodValue() - 你是对的,qpp不会为你生成这段代码。
如果要确保在继承父类的任何Qore语言类中实现该方法,请确保在qpp文件中定义一个定义父类的抽象Qore方法。