Qore双类实现(C ++ / Qore)和从C ++核心

时间:2017-02-17 20:53:45

标签: qore

我需要在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 来实现它(在将常规对象作为参数传递时会出现额外的问题)。

1 个答案:

答案 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方法。