首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用cppyy在python中创建子类?

如何使用cppyy在python中创建子类?
EN

Stack Overflow用户
提问于 2020-06-10 12:34:47
回答 1查看 207关注 0票数 1

我使用cppyy来允许python调用C++函数和类。但我不知道如何创建导入的C++函数的子类。

这是我的问题。

代码语言:javascript
复制
import cppyy
cppyy.include('/include/HSTradeApi.h')  //include the CHSTradeSpi class
cppyy.load_library('win64/HSTradeApi')

下面是听力器文件中的类CHSTradeSpi。我简化了它,保持了这门课的第一个乐趣。

代码语言:javascript
复制
// C++ header file
#include "HSStruct.h"   // this header file seems not directly related to my problem
class  CHSTradeSpi
{
public:
    virtual void OnFrontConnected(){};
};

然后,我尝试在CHSTradeSpi中创建一个子类,以添加更多的函数。

代码语言:javascript
复制
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++来获取一个实例。

代码语言:javascript
复制
#include "../include/HSDataType.h"
#include "../include/HSTradeApi.h"
class CMyTradeSpi : public CHSTradeSpi
{
public:
     void OnFrontConnected();
};

然后我导入到python

代码语言:javascript
复制
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 {“的错误点

代码语言:javascript
复制
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中创建一个实例。

代码语言:javascript
复制
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,也没有运行任何东西。我也不知道原因。谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-06-10 22:34:27

它不是关于基类是一个抽象基,而是关于它没有一个虚拟析构函数。没有虚拟析构函数意味着,如果通过带有基类类型的指针删除派生实例,则不调用派生类的析构函数。如果是OTOH,则析构函数是虚拟的,这两个构造函数都会按其应有的方式调用。Iow.,w/o是一个虚拟析构函数,python实例将泄漏(永远不会被垃圾收集),因此此类基类的派生将被禁用。

如果您无论如何都想继续,您可以使用虚拟析构函数插入一个虚拟类。如果通过原始基在C++中删除实例,您仍然会遇到同样的问题。但是,如果您能够确保python实例只在python中被删除,那么您就可以了。下面是这样一个解决办法的例子:

代码语言:javascript
复制
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释放。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62303724

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档