mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-04-30 19:09:26 +08:00
* Fix #201: Add class inheritance support with Derived : Base syntax Classes can now inherit methods and attributes from a base class using C++-style syntax: `class Derived : Base { ... }`. Base class methods and attributes are automatically available on derived objects. Derived classes can override base methods by defining a method with the same name. Inheritance relationships are tracked to support proper type matching in the dispatch system. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Address review: use implicit derived-to-base matching instead of copying base class functions Instead of copying all base class methods/attributes into derived classes, make the type matching system recognize inheritance relationships. Base class methods now naturally match derived objects through dynamic_object_typename_match, and dispatch ordering ensures derived overrides are preferred over base methods. This is simpler (net -25 lines) and avoids duplicating function registrations. Requested by @lefticus in PR #641 review. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add tests for passing derived objects to functions expecting Base Tests cover: free functions calling base methods on derived objects, polymorphic dispatch through containers, base attribute access on derived objects, and multi-level inheritance (GrandChild : Derived : Base). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add typed parameter tests for class inheritance Use typed function signatures (e.g., `def call_do_something(Base obj)`) instead of untyped parameters to test that derived objects are accepted by functions expecting a base type, with correct polymorphic dispatch. Requested by @lefticus in PR #641 review. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: leftibot <leftibot@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
138 lines
2.6 KiB
ChaiScript
138 lines
2.6 KiB
ChaiScript
|
|
class Base
|
|
{
|
|
attr x
|
|
|
|
def Base()
|
|
{
|
|
this.x = 10
|
|
}
|
|
|
|
def do_something()
|
|
{
|
|
return this.x * 2
|
|
}
|
|
}
|
|
|
|
class Derived : Base
|
|
{
|
|
attr y
|
|
|
|
def Derived()
|
|
{
|
|
this.x = 10
|
|
this.y = 20
|
|
}
|
|
|
|
def do_other()
|
|
{
|
|
return this.y * 3
|
|
}
|
|
}
|
|
|
|
// Test basic inheritance - derived can call base methods
|
|
auto d = Derived()
|
|
assert_equal(10, d.x)
|
|
assert_equal(20, d.y)
|
|
assert_equal(20, d.do_something())
|
|
assert_equal(60, d.do_other())
|
|
|
|
// Test base class still works independently
|
|
auto b = Base()
|
|
assert_equal(10, b.x)
|
|
assert_equal(20, b.do_something())
|
|
|
|
// Test method override
|
|
class Derived2 : Base
|
|
{
|
|
def Derived2()
|
|
{
|
|
this.x = 5
|
|
}
|
|
|
|
def do_something()
|
|
{
|
|
return this.x * 100
|
|
}
|
|
}
|
|
|
|
auto d2 = Derived2()
|
|
assert_equal(500, d2.do_something())
|
|
|
|
// Test passing a derived object to an untyped free function
|
|
def call_do_something_untyped(obj) {
|
|
return obj.do_something()
|
|
}
|
|
|
|
auto d3 = Derived()
|
|
assert_equal(20, call_do_something_untyped(d3))
|
|
assert_equal(20, call_do_something_untyped(Base()))
|
|
|
|
// Test typed functions: parameter declared as Base, accepts derived objects
|
|
def call_do_something(Base obj) {
|
|
return obj.do_something()
|
|
}
|
|
|
|
assert_equal(20, call_do_something(Base()))
|
|
assert_equal(20, call_do_something(d3))
|
|
|
|
// Test typed function accessing base attributes on a derived object
|
|
def get_x(Base obj) {
|
|
return obj.x
|
|
}
|
|
|
|
assert_equal(10, get_x(d3))
|
|
assert_equal(10, get_x(Base()))
|
|
|
|
// Test polymorphic dispatch through typed function: derived override is called
|
|
auto d4 = Derived2()
|
|
assert_equal(500, call_do_something(d4))
|
|
|
|
// Test mixing base and derived in a container, calling base methods
|
|
var objects = [Base(), Derived(), Derived2()]
|
|
assert_equal(20, objects[0].do_something())
|
|
assert_equal(20, objects[1].do_something())
|
|
assert_equal(500, objects[2].do_something())
|
|
|
|
// Test that derived objects still report correct type
|
|
auto d5 = Derived()
|
|
assert_true(d5.is_type("Derived"))
|
|
|
|
// Test multi-level inheritance
|
|
class GrandChild : Derived
|
|
{
|
|
attr z
|
|
|
|
def GrandChild()
|
|
{
|
|
this.x = 1
|
|
this.y = 2
|
|
this.z = 3
|
|
}
|
|
|
|
def do_grandchild()
|
|
{
|
|
return this.z * 4
|
|
}
|
|
}
|
|
|
|
auto gc = GrandChild()
|
|
assert_equal(1, gc.x)
|
|
assert_equal(2, gc.y)
|
|
assert_equal(3, gc.z)
|
|
assert_equal(2, gc.do_something()) // Base method
|
|
assert_equal(6, gc.do_other()) // Derived method
|
|
assert_equal(12, gc.do_grandchild()) // Own method
|
|
|
|
// Test passing grandchild to typed Base function (multi-level inheritance)
|
|
assert_equal(2, call_do_something(gc))
|
|
assert_equal(1, get_x(gc))
|
|
|
|
// Test typed function expecting mid-level type
|
|
def call_do_other(Derived obj) {
|
|
return obj.do_other()
|
|
}
|
|
|
|
assert_equal(6, call_do_other(gc))
|
|
assert_equal(60, call_do_other(Derived()))
|