我使用cppyy来允许python调用C++函数和类。但我不知道如何创建导入的C++函数的子类。
这是我的问题。
import cppyy
cppyy.include('/include/HSTradeApi.h') //include the CHSTradeSpi class
cppyy.load_library('win64/HSTradeApi')下面是听力器文件中的类CHSTradeSpi。我简化了它,保持了这门课的第一个乐趣。
// C++ header file
#include "HSStruct.h" // this header file seems not directly related to my problem
class CHSTradeSpi
{
public:
virtual void OnFrontConnected(){};
};然后,我尝试在CHSTradeSpi中创建一个子类,以添加更多的函数。
class CTradeSpi(cppyy.gbl.CHSTradeSpi):
def __init__(self, tapi):
super().__init__(self) // is this line wrong?
self.tapi = tapi
def OnFrontConnected(self) -> "void":
print("OnFrontConnected")
authfield = cppyy.gbl.CHSReqAuthenticateField() # defined in HSSruct.h
authfield.BrokerID = BROKERID
authfield.UserID = USERID
authfield.AppID = APPID
authfield.AuthCode = AuthCode #
self.tapi.ReqAuthenticate(authfield, 0)
print("send ReqAuthenticate ok")它失败了,并说"CHSTradeSpi不是一个可接受的基础:没有虚拟析构函数“。我知道CHSTradeSpi是抽象类,但是如何创建它的子类呢?
先谢谢你。
*更新*
非常感谢维姆·拉夫里森。我改变了计划。首先,我用CMyTradeSpi编写了一个派生类C++来获取一个实例。
#include "../include/HSDataType.h"
#include "../include/HSTradeApi.h"
class CMyTradeSpi : public CHSTradeSpi
{
public:
void OnFrontConnected();
};然后我导入到python
import cppyy
cppyy.include('/include/HSTradeApi.h') //include the CHSTradeSpi class
cppyy.load_library('win64/HSTradeApi')
cppyy.include('/include/newTrade.h') ## class CMyTradeSpi in it
virt_spi = AddVirtualDtor(cppyy.gbl.CMyTradeSpi) # call CMyTradeSpi
class CTradeSpi(virt_spi):
def __init__(self, tapi):
virt_spi.__init__(self)
self.tapi = tapi我得到了"public CMyTradeSpi {“的错误点
input_line_29:18:3: error: call to implicitly-deleted default constructor of '::workaround::CMyTradeSpiWithVDtor'
Dispatcher1() {}
^
input_line_27:2:34: note: default constructor of 'CMyTradeSpiWithVDtor' is implicitly deleted because base class 'CMyTradeSpi' has no default constructor
class CMyTradeSpiWithVDtor : public CMyTradeSpi {它似乎也需要一个构造函数。
*更新2*
由于上面的错误,我尝试使用Python在python中创建一个实例。
import time
import cppyy
import abc
cppyy.include('/include/HSTradeApi.h')
cppyy.load_library('win64/HSTradeApi')
def AddVirtualDtor(cls):
#dname = cls.__name__+"WithVDtor"
cppyy.cppdef("""namespace workaround {{
class {0}WithVDtor : public {1} {{
public:
using {0}::{0};
virtual ~{0}WithVDtor() {{}}
}}; }}""".format(cls.__name__, cls.__cpp_name__))
return getattr(cppyy.gbl.workaround, "{0}WithVDtor".format(cls.__name__))
spi = AddVirtualDtor(cppyy.gbl.CHSTradeSpi)
class CTradeSpi(spi):
__metaclass__ = abc.ABCMeta
def __init__(self, tapi):
spi.__init__(self)
self.tapi = tapi
def OnFrontConnected(self) -> "void":
print("OnFrontConnected")
authfield = cppyy.gbl.CHSReqAuthenticateField()
authfield.HSAccountID = ACCOUNTID
authfield.HSPassword = PASSWORD
authfield.HSAppID = APPID
authfield.HSAuthCode = AuthCode #
self.tapi.ReqAuthenticate(authfield, 0)
print("send ReqAuthenticate ok")没有任何错误。但是它没有打印出"OnFrontConnected",所以我猜,类CTradeSpi( spi )没有覆盖spi,也没有运行任何东西。我也不知道原因。谢谢。
发布于 2020-06-10 22:34:27
它不是关于基类是一个抽象基,而是关于它没有一个虚拟析构函数。没有虚拟析构函数意味着,如果通过带有基类类型的指针删除派生实例,则不调用派生类的析构函数。如果是OTOH,则析构函数是虚拟的,这两个构造函数都会按其应有的方式调用。Iow.,w/o是一个虚拟析构函数,python实例将泄漏(永远不会被垃圾收集),因此此类基类的派生将被禁用。
如果您无论如何都想继续,您可以使用虚拟析构函数插入一个虚拟类。如果通过原始基在C++中删除实例,您仍然会遇到同样的问题。但是,如果您能够确保python实例只在python中被删除,那么您就可以了。下面是这样一个解决办法的例子:
import cppyy
cppyy.cppdef("""
class CHSTradeSpi {
public:
virtual void OnFrontConnected() = 0;
};""")
def AddVirtualDtor(cls):
dname = cls.__name__+"WithVDtor"
cppyy.cppdef("""namespace workaround {{
class {0}WithVDtor : public {1} {{
public:
using {0}::{0};
virtual ~{0}WithVDtor() {{}}
}}; }}""".format(cls.__name__, cls.__cpp_name__))
return getattr(cppyy.gbl.workaround, "{0}WithVDtor".format(cls.__name__))
class CTradeSpi(AddVirtualDtor(cppyy.gbl.CHSTradeSpi)):
def __init__(self, tapi):
super(CTradeSpi, self).__init__()
self.tapi = tapi
def OnFrontConnected(self):
# etc ...
pass编辑:克服构造函数问题的一个简单方法是在using旁边添加一个确实存在的构造函数。这样,就不会生成缺省值。但是,我无法编写这样做的简单代码(您可以内省基类以生成一个类,但它并不漂亮)。如果您只有一个类,那么这可能是一个解决方案。如果有这样的构造函数(根据需要更改参数),只需在代码中的{0}WithVDtor(int i) : {0}(i) {{}}前面添加例如using。
我正在进行更改,看看是否可以放松对虚拟析构函数的要求。我在一个案子里还有一次坠机事故。
您不能替换元类:是元类插入蹦床,所以通过使用abc.ABCMeta禁用。是的,没有错误,但也没有调度。
UPDATE:作为支持跨语言屏障的多重继承的更改的一部分,C++侧保留的对象现在是蹦床,因此基础中不再需要虚拟析构函数。仍然存在一个警告,同样的警告是:在C++端删除将泄漏Python。不久将于1.7.2释放。
https://stackoverflow.com/questions/62303724
复制相似问题