Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

beginExtendClass<> does not currently support multiple inheritance (vtables) #88

Open
demianmnave opened this issue Sep 1, 2015 · 0 comments

Comments

@demianmnave
Copy link

This isn't really a bug report, so much as an FYI. static_cast<> doesn't work as expected when the type of the source pointer has more than one base with a virtual table. This causes CppObject::get() to return the wrong pointer when T has multiple base virtual tables.

I was able to work around the problem for my application (in VC++2013) with a few pretty simple modifications:

  • added a new objectPtr(void* class_id, bool is_const) overload to CppObject that calls objectPtr() by default;
  • implemented a helper template, Upcast, with a function void* get(Derived* d, void* other_id, bool is_const) that returns d when not specialized for a particular class, or that, when specialized, should search up the hierarchy from d for a base class with matching class_id;
  • changed calls to objectPtr() in CppObject methods into calls to objectPtr(class_id,is_const);
  • implemented an override of objectPtr(void*,bool) in CppObjectSharedPtr<SP,T> that uses Upcast::get() to search for the matching base class; and
  • implemented specializations of Upcast<> for my class hierarchy (used macros, but could also be done with C++11 for a class hierarchy having consistently-defined in-class typedef's of base and derived classes).

Here are snippets of the relevant changes:

  • Unspecialized Upcast<>:
    template<class Derived> struct Upcast {
      static void* get(Derived* derived, void* other_id, bool is_const) {
        void* class_id = CppObject::getClassID<Derived>(is_const);
        return (class_id == other_id) ? derived : nullptr;
      }
    };
  • CppObject:
    virtual void* objectPtr(void* /*class_id*/, bool /*is_const*/) {
      return objectPtr();
    }

    template <typename T>
    static T* cast(lua_State* L, int index, bool is_const)
    {
      void* class_id = getClassID<T>(is_const);
      CppObject* object = getObject(L, index, class_id, is_const, false, false);
      return object ? static_cast<T*>(object->objectPtr(class_id, is_const)) : nullptr;
    }

    template <typename T>
    static T* get(lua_State* L, int index, bool is_const)
    {
      void* class_id = getClassID<T>(is_const);
      return static_cast<T*>(getObject<T>(L, index, is_const)->objectPtr(class_id, is_const));
    }
  • CppSharedObjectPtr:
    virtual void* objectPtr(void* class_id, bool is_const) override
    {
      auto derived = const_cast<T*>(&*m_sp);
      return Upcast<T>::get(derived, class_id, is_const);
    }
  • Example specialization:
template<> struct Upcast<ClassA> {
  typedef ClassA Derived;
  typedef ClassA::Base Base;
  static void* get(Derived* derived, void* other_id, bool is_const) {
    void* class_id = CppObject::getClassID<Derived>(is_const);
    return (class_id == other_id) ? derived : Upcast<Base>::get(derived, other_id, is_const);
  }
};  

This did the trick for my current set of test cases. CppObjectPtr would need to be made into a template class, but otherwise it could be modified the same was as CppSharedObjectPtr. I am currently only using CppSharedObjectPtr (via boost::intrusive_ptr), so I did not make this modification.

Hope this can be of use to someone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant