python永远不能调用c ++ dll或包含继承逻辑的文件?

时间:2019-02-12 08:48:04

标签: python c++ dll virtual ctypes

class A{
  A();
  void a();
  virtual void v();
}

将此文件保存到liba.so

class B : A {
  B();
  void b();
  void v();
}
extern "C" {
  A* newB() {
    return new B();
  }
  void calla(A*b) {
    b->a();
  }
  void callv(A*b) {
     b->v();
  }
}

将此文件保存到libb.so

在python中:

from ctypes import cdll 
lib = cdll.LoadLibrary('./libb.so')

class B(object):
  def __init__(self):
    self.obj = lib.newb()
  def a(self):
    lib.calla(self.obj)
  def v(self):
    lib.callv(self.obj)

b = B()
b.a()  # call base class function, that's ok
b.v()  # call derive class virtual function , segment fault!

这是否意味着python无法使用包含继承逻辑的dll?

似乎python无法调用c ++类,因为其函数入口更改为bc继承逻辑,任何人都可以谈论此事吗?

谢谢

1 个答案:

答案 0 :(得分:0)

注释

我准备了一个完整的(并且是虚拟的)示例来说明这种行为。

a.h

#pragma once
#define COUT() std::cout << __FILE__ << ":" << __LINE__ << "(" << __FUNCTION__ << ")\n"

#if defined(_WIN32)
#  define DLL_EXPORT __declspec(dllexport)
#else
#  define DLL_EXPORT
#endif


class DLL_EXPORT A {
public:
    A();
    virtual ~A();
    void a();
    virtual void v();
};

a.cpp

#include "a.h"
#include <iostream>


A::A() {
    COUT();
}

A::~A() {
    COUT();
}

void A::a() {
    COUT();
}

void A::v() {
    COUT();
}

b.h

#pragma once
#include "a.h"


class B : public A {
public:
    B();
    void b();
    void v();
};


extern "C" {
    DLL_EXPORT A *newB() {
        return new B();
    }

    DLL_EXPORT void calla(A *b) {
        b->a();
    }

    DLL_EXPORT void callv(A *b) {
        b->v();
    }

    DLL_EXPORT void delB(A *b)
    {
        delete b;
    }
}

b.cpp

#include "b.h"
#include <iostream>


B::B() : 
    A() {
    COUT();
}

void B::b() {
    COUT();
}

void B::v() {
    COUT();
}

code.py

#!/usr/bin/env python3

import sys
import ctypes


LIB_NAME = "./libb.so"


class B(object):

    def __init__(self, lib_name=LIB_NAME):
        self.lib = ctypes.cdll.LoadLibrary(lib_name)
        self.lib.newB.restype = ctypes.c_void_p
        self.obj = self.lib.newB()

    def a(self):
        self.lib.calla.argtypes = [ctypes.c_void_p]
        self.lib.calla(self.obj)

    def v(self):
        self.lib.callv.argtypes = [ctypes.c_void_p]
        self.lib.callv(self.obj)

    def __del__(self):
        self.lib.delB.argtypes = [ctypes.c_void_p]
        self.lib.delB(self.obj)
        self.obj = None
        self.lib = None


def main():
    b = B()
    b.a()
    b.v()


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

输出

[cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q054646019]> ls
a.cpp  a.h  b.cpp  b.h  code.py
[cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q054646019]> g++ -shared -fPIC -o liba.so a.cpp
[cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q054646019]> g++ -shared -fPIC -o libb.so b.cpp ./liba.so
[cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q054646019]> ls
a.cpp  a.h  b.cpp  b.h  code.py  liba.so  libb.so
[cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q054646019]> python3 code.py
Python 3.6.4 (default, Jan  7 2018, 15:53:53)
[GCC 6.4.0] on cygwin

a.cpp:6(A)
b.cpp:7(B)
a.cpp:14(a)
b.cpp:15(v)
a.cpp:10(~A)