Re: True Inheritable Classes In C (was Generic Interface)

Hammond, Mark (MHammond@jm.cmutual.com.au)
Thu, 09 Mar 95 14:28:00 PST

>This is what I am working on. I am trying to make the MFC class
>hierarchy visible from Python so I can port some GUI code I have
>running under Tcl/Tk to NT. I just got some code working which allows
>Python to create C++ objects and inherit from the C++ hierarchy.
>The method works without needing any new Python features.

Oh oh. I already have a large subset of MFC exposed to Python. My list of
objects supported is something like:
Window
CFrameWnd
CMDIClientWnd
CMDIFrameWnd
CView
CEditView
CDialog
CFileDialog
CSplitterWnd
CMenu
CDC
CFont
CToolBar
CControl
CButton
CListBox
CEdit
CRadioButton
CBitmap
CDocument
and some extras
Hierarchical list, DLL object,

So I hope we are not duplication too much work. Maybe I should have
publicised mine more, but I have been releasing it on and off for 6 months
now.

>First create the new C++ classes you need, and subclass them from
>the GUI C++ class library you are using. For example, create a
>C++ class CMyView subclassed from CView. In Python create a Python
>class CView in a module and import it into your program. Your program
>creates a class CMyView subclassed from CView (in Python). The two
>classes Python CMyView and C++ CMyView are twins.

I came into a problem here. It is not always possible to create a C++
derived class. For example, some of the paint function pass you a CDC *.
It is not really possible (or not worth!) creating a CMyDC, as you did not
construct the object.

Another example is where you want an arbitary window. eg, Consider the
CWnd::GetWindow function. Lets say to make this call to get the parent
window. You really need a way of returing to Python an object for a C++
object that already exists - ie, from an already existing CWnd *.

>Next define all the member functions in Python CView that you care
>about. These are equal to the corresponding functions in C++ CView.
>The body is a call to an interface module my_module.cpp which calls
>the corresponding function in C++ CMyView, which inherits fron C++
>CView and the rest of the class hierarchy. You can override these
>functions (members) in Python CMyView if you want.

Yes, but this doesnt really give you _true_ inheritable classes. This is
the same technique that the FAQ suggests for "simulating" it.
Of couse, this technique is totally reasonable (and what I use too) but not
really providing _true_ inheritence.

I tried messing with the __getattr__ "magic" member, but gave up, but I
think a solution could be found here.

Note that my C++ code does implement true inheritance internally - but not
from Python.

eg, when I define my FrameWindow in C++, I tell it that it is "derived" from
the Window object. Therefore, the C++ FrameWindow object automatically
inherits from the C++ Window object. But I cant get my Python objects to
inherit from my C++ objects.

I think I better give an example (not real method names!)

>>> wnd = win32ui.GetWindow()
This calls my C++ extension module, and returns a window object. This
window object is implemented in the module in C++, and has a pointer to an
MFC CWnd object, and a map entry from the MFC CWnd.

>>> frame = wnd.GetParent()
This calls a method on the window object, and returns a frame window object.
Again, the frame window object is implemented in C++, nad has a pointer to
an MFC CFrameWnd.
>>> frame.SetWindowText('Hi')
SetWindowText is really a method on a window object, and not a specific
method on a frame window. All the frame window definition (in the C++) need
do is to say it is inherited from a window object, and all window methods
are available.

But what I cant do (and what I believe this thread is about) is:
>>> def PythonWindow( inherit_from_a_window_object )

but instead must say:
>>> def PythonWindow():
... def __init__():
... self.wnd = Get_A_C++_Window_Object
... def SetWindowText(self, text):
... self.wnd.SetWindowText(text)

>The Python CMyView and C++ CMyView are twins, and a Python call on one
>must convert to a C++ call on the other and vice versa. So set up
>two dictionaries in C++ to convert Python object* to/from C++
>CObject*. In a GUI environment using a black box class library like
>MFC this is tricky. The only thing that works, and the thing that
>makes the most sense, is to create the two dictionaries in the C++
>class constructors, so you must arrange for the Python object*
>to be available then.

My technique is slightly different. I use only one map. In the C++ code,
where I define the new types for the objects I am returning, I simply store
a pointer to the MFC object. This way, going from an "object *" to a
"CObject *" is direct pointer access, but going from a "CObject *" back to a
"object *" is via a map. This map must be looked up to perform
message/command callbacks, etc, but for simply making a call from Python to
the C++ method requires no map lookup at all.
>
>BTW, "inherit from a C++ class hierarchy" comes up often and is
>mentioned in the FAQ. And it is a very interesting issue. To
>my mind there is no solution, and the problem is impossible. More
>exactly, the "solution" is to write a compiler to convert C++
>class declarations to the corresponding classes, and make my_module.cpp
>too. The C++ class hierarchy is "immutable" in the Python sense, so
>a hier.pyc seems a fair representation. Lacking a C++ class compiler,
>the Python CView and my_module.cpp are written by hand.

Yes - stuff still needs to be added by hand, but if you could implement my
example above, it would be a big help. As I said, some __getattr__ tricks
may do the job.

Going the full way to _really_trully_true_ inheritance is probably a pipe
dream.

Regards,

Mark (MHammond@cmutual.com.au)