python - python永远不能调用包含继承逻辑的c++ dll或so文件?
问题描述
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
在蟒蛇中:
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继承逻辑,有人能谈谈吗?
谢谢
解决方案
备注:
- 代码(C或Python)均未编译OOTB。那是因为它不完整或不正确。检查[SO]: How to create a Minimal, Complete, and Verifiable example (mcve)了解如何格式化您的问题
- [Python 3]:ctypes - Python 的外部函数库可能有用
- 虚方法与错误无关,只是巧合,错误是因为未指定argtypes和restype。检查[SO]:不同操作系统上的python ctypes问题(@CristiFati的答案)([SO]:Python ctypes cdll.LoadLibrary,实例化一个对象,执行它的方法,截断私有变量地址(@CristiFati的答案),或许多其他)细节
我准备了一个完整的(和虚拟的)示例来说明这种行为。
啊:
#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();
}
: _
#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();
}
代码.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)
推荐阅读
- android - 如何通过 webView 应用程序 android 上传图像 .. 这是我的应用程序
- reactjs - React Redux 是否会在每次从 Store 调度操作时重新创建整个虚拟 DOM?
- excel - 根据值excel vba更改Listview中的前景色
- mysql - 随机获取指定数量的数据,有没有更好的办法?
- python - 如何根据值拆分熊猫中的一列并创建新列?
- java - 如何在 Apache Beam 中同时使用 MapElements 和 KV?
- css - IE11 无法识别 z-index:-1
- opengl - 无法使用我的图像获得透视
- windows - 如何从命令提示符运行 ffmpeg
- javascript - 如何清除和覆盖表格结果