用于创建/维护外部结构的 C++ 构造函数链接

Posted

技术标签:

【中文标题】用于创建/维护外部结构的 C++ 构造函数链接【英文标题】:C++ Constructor chaining to create/maintain an external structure 【发布时间】:2020-09-16 14:28:30 【问题描述】:

我正在尝试使用 python Ctypes 来连接我提供的 C++ 类。在读/写成员数据和调用方法方面,我已经完成了大部分工作。但是我试图锻炼的课程(称之为 ClassA)依赖于一个外部课程(称之为 classB)。见:

//main.cc   This is existing caller code. everything is c++ so using it is easy
include "ClassA.hh"
include "ClassB.hh"

void main() 

ClassB objB(x,y,z);

ClassA objA(a,b, &objB);

objA.DoStuff();

但我还没有准备好通过 ctypes 在 python 中绑定和公开 classB。没用过ctypes的,基本都是写一些C绑定,用python调用。 A 类绑定可能如下所示:

//at the bottom of ClassA.hh
extern "C" 
    ClassA* ObjaNew(int x, int y)  return new ClassA(x,y);
    void ObjaDoStuff(ClassA* objPtr)  objPtr->DoStuff();

然后python中的调用代码可能是这样的

mylib = ctypes.cdll('mylib.so')
myPyObj = mylib.ObjaNew(5,6)   // executes ObjaNew
mylib.ObjaDoStuff(myPyObj)     // executes ObjaDoStuff

重要的一点是 python ctypes 仅支持 native-ish c 类型。通过 Ctypes 接口创建、传递或获取类或结构或 std::vector 是可行的。例如:此链接是需要编写才能分配 c++ 向量的代码:https://***.com/a/16887455/2312509

所以,我想我想做的是:

//classA.hh

class ClassA
public:
    ClassA(int a, int b, ClassB* p_objb)   //This is the existing constructor
        ; //whatever
        m_objb = p_objb;
    
    ClassA(int a, int b)               // This is my new constructor
        ClassB *objB = new ClassB(x,y,z);
        ClassA(a,b,objB);
    

我已经完成了这个并且它可以编译,但我还不能真正运行它。我担心 objB 被释放了,因为我看不到它是一个成员,尽管它是在构造函数的主体中分配的。我觉得如果对 new 的调用被分配给成员数据指针,那是对的,因为它是这样工作的,但是分配给本地指针,然后传递本地指针可能会失败。

我想我可以创建一个继承自两者的子类,例如:

ClassAB: public b():public a()
//But the A constructor still would need to NOT rely on the existence of ObjB
    m_objb = &this;
    

我没有写过一大堆C++,所以我不知道正确答案是什么,但我觉得这不是一个新的或新颖的概念。

【问题讨论】:

我不是 Python 方面的专家,但从 C++ 方面来看,这个问题让我感到困惑。您是否试图以一种拥有 B 和一种不拥有 B 的方式构建一个类。如果 A 被销毁,您期望 B 实例会发生什么? @JVApen A的调用者的写法,A是唯一使用B的东西,所以从我的角度来看,我想我应该有一个析构函数知道我是否创建/分配B 并且应该删除它或不适当地删除它。 python部分不是超级相关的,除了python的Ctypes基本上支持int、float、chars和指向这些和void的指针的概念,所以将任何外部的东西传递给不是其中之一的类都是PITA。 在这种情况下,您是否需要 B 比 A 活得更久,还是可以将所有权转移到 A 中? 我不需要 B 比 A 更长寿。我发现自己想要重构,以便 A 是 B 的子类。 完美,看我的回答 【参考方案1】:

看这个问题,很明显你必须花一些时间学习在 C++ 中使用对象的基础知识。

在这种情况下,我建议您执行以下操作:

class ClassA
     int m_a;
     int m_b;
     ClassB m_objb;
public:
    ClassA(int a, int b, ClassB &&p_objb)
        : m_aa
        , m_bb
        , m_objbstd::move(p_objb)
     
    
    ClassA(int a, int b)
       : ClassA(a, b, ClassBx, y, z)
    
    
;

通过使 ClassB 成为 Class a 的成员,您不必担心内存分配或所有权,因为这是隐含的。

调用代码如下所示:

 ClassB objB(x,y,z);
 ClassA objA(a,b, std::move(objB));
 objA.DoStuff();

或者更简单:

 ClassA objA(a,b, ClassB(x, y, z));
 objA.DoStuff();

这最后清楚地表明ClassB只需要构造ClassA,你不能在move之后写一个use。

如果您想了解更多信息,我可以向了解 Java 的人推荐我的另一篇解释相同基础知识的帖子:https://codereview.stackexchange.com/questions/241354/remaking-a-1998-rts-game-in-c/241647#241647

【讨论】:

【参考方案2】:

所以,我现在似乎运行的是一个瘦接口类:

//classAInterface.cc
#include "classA.hh"  // These are unchanged
#include "classB.hh"

class ClassAInterface 
public:
    ClassAInterface(int a, int b);
    ClassB *m_objb;
    ClassA *m_obja;
;
ClassAInterface(int a, int b)
    m_objb = new ClassB();
    m_obja = new ClassA(a,b,m_objb);


extern "C" 
    ClassAInterface* ObjaNew(int x, int y)  return new ClassAInterface(x,y);
    void ObjaDoStuff(ClassAInterface* objIntPtr)  objIntPtr->m_obja->DoStuff();


// The python is the same
mylib = ctypes.cdll('mylib.so')
myPyObj = mylib.ObjaNew(5,6)   // executes ObjaNew
mylib.ObjaDoStuff(myPyObj)     // executes ObjaDoStuff

这似乎正在工作,并允许我实际上不更改我想要接口的类。它有一些缺点,因为我真正的 ClassA 依赖它的调用者来做某些事情的方式还有其他令人不快的地方。

【讨论】:

请注意,您还需要一个函数来删除myPyObj,否则在 Python 中会出现内存泄漏。您还可以研究包装生成器,例如 SWIG,以便在 Python 中自动包装 C++ 类。

以上是关于用于创建/维护外部结构的 C++ 构造函数链接的主要内容,如果未能解决你的问题,请参考以下文章

C ++中的结构构造函数?

构造函数用于创建类的实例对象,构造函数名应与类名相同,返回类型为void.

传递给类构造函数的 C++ 字符串 - 链接器错误

在 C++ 中的类构造函数中初始化结构数组

C结构未初始化的外部构造函数

c++ 在创建时将构造函数参数从父对象传递给子对象