Native inheritance/base classes and multi inheritance
cykoder opened this issue · comments
Hey! Great library.
Is it possible currently to define a native C++ class's base/parent class? Furthermore, is it possible for that definition to include the parents base class and so on. I noticed an in-progress/todo commented function base
, I tried to use it and it seemed to work to some extent but there are issues. The prototype properties seem to be there form the parent, but using any of those methods or properties causes an exception "ParentClass object expected"
In essence I would like to do:
module.class_<Point>("Point")
.constructor<int, int>()
.fun<&Point::x>("x")
.fun<&Point::y>("y")
.fun<&Point::norm>("norm");
module.class_<Point3D>("Point3D")
.base<Point>()
.constructor<int, int, int>()
.fun<&Point3D::z>("z")
where
class Point3D : public Point { }
then in JS:
const point = new Point3D(1, 2, 3);
console.log('point xyz', point.x, point.y, point.z);
Echo above on all points :)
- Great library!
- I'd also love it if class inheritance was supported in this way
Hello. The problem is that parentclass' methods expect only parentclass classid. To make inheritance work they would need to check if the id is of any of the inherited classes, which might be not very quick in some cases.
Another way is to disable the classid check, which would probably make a program crash if you pass wrong class type from JS, instead of an exception being thrown.
Here's the patch to disable the check:
diff --git a/quickjspp.hpp b/quickjspp.hpp
--- a/quickjspp.hpp (revision e39f505ee6eedc1e0caae046b9502dfb89daec89)
+++ b/quickjspp.hpp (date 1629647676903)
@@ -767,7 +767,9 @@
/// @throws exception if #v doesn't have the correct class id
static const std::shared_ptr<T>& unwrap(JSContext * ctx, JSValueConst v)
{
- auto ptr = reinterpret_cast<std::shared_ptr<T> *>(JS_GetOpaque2(ctx, v, QJSClassId));
+ // auto ptr = reinterpret_cast<std::shared_ptr<T> *>(JS_GetOpaque2(ctx, v, QJSClassId));
+ // disable classid check to make parent methods work
+ auto ptr = reinterpret_cast<std::shared_ptr<T> *>(JS_GetOpaque2(ctx, v, JS_GetClassID(v)));
if(!ptr)
throw exception{};
return *ptr;
@@ -803,8 +805,7 @@
static T * unwrap(JSContext * ctx, JSValueConst v)
{
- auto ptr = reinterpret_cast<std::shared_ptr<T> *>(JS_GetOpaque2(ctx, v,
- js_traits<std::shared_ptr<T>>::QJSClassId));
+ auto ptr = reinterpret_cast<std::shared_ptr<T> *>(JS_GetOpaque2(ctx, v, JS_GetClassID(v)));
if(!ptr)
throw exception{};
return ptr->get();
@@ -1352,7 +1353,7 @@
return *this;
}
- /* TODO: needs casting to base class
+ /* TODO: needs casting to base class*/
template <class B>
class_registrar& base()
{
@@ -1364,7 +1365,7 @@
throw exception{};
return *this;
}
- */
+
~class_registrar()
{
Another way is to keep a flag whether a class is inherited and disable the id check in this case, but it feels kind of hacky.
Yep that class ID check removal seems to have done it, thanks for that! I would argue that any developer should ensure the right type is always passed, but I understand thats not always easy and isnt so user friendly. Perhaps it could be a library configuration option to determine if the class id check should exist for multi-inheritance or not? For my case its game engine scripting so if it'll be slow I'd rather just disable it, for some non-performant use cases/debug mode the extra validation may be useful.
Should I keep the issue open for future reference incase you get around to solving this problem, or shall I close it?
EDIT: On further testing found one thing that isn't working. I have a method push
defined like:
void ClassName::push(ClassName* comp);
and I have ChildClassName
which inherits ClassName
. I can construct it and access its members just fine now, however if I call classNameBase.push(childObject)
where classNameBase
is of type ClassName
and childObject
is of type ChildClassName
I get an error that it expected a ClassName
object. Looks like perhaps another class type/id check somewhere?
Sam, did you solve this one? I'm about to do exactly the same thing (classNameBase.push(childObject)
) - also for game engine scripting :)
I didn't unfortunately, although I didn't have much spare time to dive into quickjshpp/quickjs again. @ftk could fixing this be as simple as disabling class ID check like before in another place?
Sam, I found a start toward a possible solution. I'm about to implement this. It's the (current) last major hurdle to getting my project up and running.
Updated the patch in #24 (comment)
Thank ftk. That is perfect. Running like a charm!