polymorphism.txt

来自「Boost provides free peer-reviewed portab」· 文本 代码 · 共 223 行

TXT
223
字号
.. Copyright David Abrahams 2006. Distributed under the Boost.. Software License, Version 1.0. (See accompanying.. file LICENSE_1_0.txt or copy at.. http://www.boost.org/LICENSE_1_0.txt)How Runtime Polymorphism is expressed in Boost.Python:-----------------------------------------------------   struct A { virtual std::string f(); virtual ~A(); };   std::string call_f(A& x) { return x.f(); }   struct B { virtual std::string f() { return "B"; } };   struct Bcb : B   {       Bcb(PyObject* self) : m_self(self) {}      virtual std::string f() { return call_method<std::string>(m_sef, "f"); }      static std::string f_default(B& b) { return b.B::f(); }      PyObject* m_self;   };   struct C : B   {      virtual std::string f() { return "C"; }   };   >>> class D(B):   ...     def f():   ...         return 'D'   ...   >>> class E(B): pass   ...When we write, "invokes B::f non-virtually", we mean:  void g(B& x) { x.B::f(); }This will call B::f() regardless of the dynamic type of x. Any otherway of invoking B::f, including through a function pointer, is a"virtual invocation", and will call the most-derived override of f().Case studies   C++\Python class       \___A_____B_____C_____D____E___       |   A   |   1       |   B   |   2     3       |   Bcb |         4           5    6       |   C   |         7     8       |1. Simple case2. Python A holds a B*. Probably won't happen once we have forced   downcasting.    Requires:         x.f() -> 'B'         call_f(x) -> 'B'   Implies: A.f invokes A::f() (virtually or otherwise)3. Python B holds a B*.    Requires:        x.f() -> 'B'        call_f(x) -> 'B'      Implies: B.f invokes B::f (virtually or otherwise)4. B constructed from Python   Requires:        x.f() -> 'B'        call_f(x) -> 'B'   Implies: B.f invokes B::f non-virtually. Bcb::f invokes B::f            non-virtually.   Question: Does it help if we arrange for Python B construction to   build a true B object? Then this case doesn't arise.5. D is a Python class derived from B   Requires:        x.f() -> 'D'        call_f(x) -> 'D'   Implies: Bcb::f must invoke call_method to look up the Python            method override, otherwise call_f wouldn't work.6. E is like D, but doesn't override f   Requires:        x.f() -> 'B'        call_f(x) -> 'B'   Implies: B.f invokes B::f non-virtually. If it were virtual, x.f()            would cause infinite recursion, because we've already            determined that Bcb::f must invoke call_method to look up            the Python method override.7. Python B object holds a C*   Requires:                x.f() -> 'C'        call_f(x) -> 'C'   Implies: B.f invokes B::f virtually. 8. C object constructed from Python   Requires:        x.f() -> 'C'        call_f(x) -> 'C'   Implies: nothing new.------Total implications:2: A.f invokes A::f() (virtually or otherwise)3: B.f invokes B::f (virtually or otherwise)4: B.f invokes B::f non-virtually. Bcb::f invokes B::f non-virtually6: B.f invokes B::f non-virtually. 7: B.f invokes B::f virtually. 5: Bcb::f invokes call_method to look up the Python methodThough (4) is avoidable, clearly 6 and 7 are not, and theyconflict. The implication is that B.f must choose its behavioraccording to the type of the contained C++ object. If it is Bcb, anon-virtual call to B::f must occur. Otherwise, a virtual call to B::fmust occur. This is essentially the same scheme we had withBoost.Python v1.Note: in early versions of Boost.Python v1, we solved this problem byintroducing a new Python class in the hierarchy, so that D and Eactually derive from a B', and B'.f invokes B::f non-virtually, whileB.f invokes B::f virtually. However, people complained about theartificial class in the hierarchy, which was revealed when they triedto do normal kinds of Python introspection.-------Assumption: we will have a function which builds a virtual functiondispatch callable Python object.     make_virtual_function(pvmf, default_impl, call_policies, dispatch_type)Pseudocode:     Get first argument from Python arg tuple     if it contains dispatch_type        call default_impl     else        call through pvmfOpen questions:   1. What about Python multiple inheritance? Do we have the right      check in the if clause above?            A: Not quite. The correct test looks like:      Deduce target type of pvmf, i.e. T in R(T::*)(A1...AN).      Find holder in first argument which holds T      if it holds dispatch_type...   2. Can we make this more efficient?          The current "returning" mechanism will look up a holder for T     again. I don't know if we know how to avoid that.  OK, the solution involves reworking the call mechanism. This is  neccesary anyway in order to enable wrapping of function objects.  It can result in a reduction in the overall amount of source code,  because returning<> won't need to be specialized for every  combination of function and member function... though it will still  need a void specialization. We will still need a way to dispatch to  member functions through a regular function interface. mem_fn is  almost the right tool, but it only goes up to 8  arguments. Forwarding is tricky if you don't want to incur copies.  I think the trick is to use arg_from_python<T>::result_type for each  argument to the forwarder.  Another option would be to use separate function, function object,  and member function dispatchers. Once you know you have a member  function, you don't need cv-qualified overloads to call it.  Hmm, while we're at this, maybe we should solve the write-back  converter problem. Can we do it? Maybe not. Ralf doesn't want to  write special write-back functions here, does he? He wants the  converter to do the work automatically. We could add  cleanup/destructor registration. That would relieve the client from  having accessible destructors for types which are being converted by  rvalue. I'm not sure that this will really save any code,  however. It rather depends on the linker, doesn't it? I wonder if  this can be done in a backwards-compatible fashion by generating the  delete function when it's not supplied?  

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?