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

make this to 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();
  }
}

make this to libb.so

in 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!

Does this mean python cant use dll including inheritance logic?

seems python cant call c++ class as its function entrance changed bc inherit logic, can anyone talk about this?

Thanks

nick huang
  • 443
  • 4
  • 12
  • 2
    `s.v()`? Where does `s` come from? `o.O` – Duck Dodgers Feb 12 '19 at 08:50
  • This doesn't answer your question (which is also quite vague), but if you need to wrap a C++ library you can take a look at pybind11: https://pybind11.readthedocs.io/en/stable/ instead of making a C-version of your lib and using ctypes. – Hannes Ovrén Feb 12 '19 at 08:56
  • typo, thats b @JoeyMallone – nick huang Feb 12 '19 at 09:00
  • thanks, i will try pybind11 @HannesOvrén – nick huang Feb 12 '19 at 09:03
  • Be aware that C++ ABI varies across different compilers and sometimes even within same compiler family but different versions. So you usually cannot even use a C++ library built with GCC from within MSVC. If you try pybind or similar, you likely will have to compile both (pybind and your dll) with the same compiler to get it running. – Aconcagua Feb 12 '19 at 09:32
  • actually, i used the same compiler. @Aconcagua – nick huang Feb 12 '19 at 09:55

1 Answers1

0

Notes:

I've prepared a full (and dummy) example, to illustrate the behavior.

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()

Output:

[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)
CristiFati
  • 38,250
  • 9
  • 50
  • 87