views:

29

answers:

1

I'm having an issue with a rather intricate interaction of C++ and Python that I'm hoping the community can help me with. If my explanation doesn't make sense, let me know in the comments and I'll try to clarify.

Our C++ code base contains a parent classes called "IODevice" which is a parent to other classes such as "File" and "Socket" and so forth. We've done this so that in much of our code we can work generically with "IODevice" objects that might actually be files or sockets or whatever we originally constructed. This all works fine within the C++ code.

We've started to build Python bindings for some of our objects. We didn't want to modify the original "File" or "Socket" classes; we created "FilePy" and "SocketPy" subclasses of the "File" and "Socket" classes. These *Py classes contain the necessary Python binding code.

Here's where the problem starts. Let's say I have a "InputProcessorPy" C++ class that has the appropriate Python bindings. I would want to be able to construct it in my Python code and pass it a "FilePy" or "SocketPy" object that the "InputProcessorPy" is going to pull data from. The Python binding code from "InputProcessorPy" looks like this:

PyObject* InputProcessor::PyMake(PyObject* ignored, PyObject *args)
{
    PyObject* cD_py;
    IODevice* inputFile;

    if (!PyArg_ParseTuple(args, "O", &cD_py))
        return NULL;

    inputFile = (IODevice*) cD_py;
    inputFile->isReadable();
    printf("------>>>> Done\n");

    return (PyObject *) new CL_InputRenderer(*inputFile, InputProcessor::Type);
}

If I run this code, I get a segmentation error when I call the isReadable() method of inputFile, which is actually a method of the IODevice base class.

If instead I do this:

    ...
    FilePy* inputFile;
    ...
    inputFile = (FilePy*) cD_py;
    inputFile->isReadable();
    ...

The code works fine in this case. This, however, is undesirable, as it assumes we are passing in a "FilePy" object, which will not be the case; it might be a "SocketPy" or "BufferPy" or "StringPy" or any other sort of "IODevice" subclass.

It seems as if the Python binding process is somehow not compatible with the C++ class inheritance structure that we're trying to use. Has anyone tried to solve an issue like this before? Are we doing our C++ inheritance wrong, or should we be doing something different in our Python bindings to make this work?

+2  A: 

Are your types FilePy and IODevice derived from PyObject? Otherwise, the C++ compiler will interpret:

inputFile = (IODevice*) cD_py;

as:

inputFile = reinterpret_cast<IODevice*> (cD_py);

rather than what you expected:

inputFile = dynamic_cast<IODevice*> (cD_py);

If the actual type passed is not PyObject, or IODevice is not related to PyObject via inheritance, there is no way for the C++ compiler or runtime to know how to find the proper vtable.

Richard Walters
As it turns out, IODevice is not related to PyObject. If this is confusing our casting, then we will need to come up with a different inheritance scheme.
dbisdorf