CBot class inheritance #540
Comments
|
Class inheritance is not currently implemented in Colobot, but probably will be after CBot refactoring. The fact that this code compiled without errors is probably a bug or a forgotten attempt to implement it. |
|
Class inheritance works for class member variables public class baseclass
{
int aaa = 1;
int bbb = 2;
void method1()
{
message("method 1");
}
void method2()
{
message("method 2");
}
}
public class extension extends baseclass
{
int ccc = 3;
int ddd = 4;
}
extern void object::TestExtends()
{
baseclass base();
extension ext = new extension;
ext.bbb = 5;//overwrites b in this class only, unless its parent is declared static
// output
message(" ext.aaa = " + ext.aaa + " ext.bbb = " + ext.bbb ); // 1 5
message("base.aaa = " + base.aaa + " base.bbb = " + base.bbb); // 1 2
}
|
|
I think if it works for fields, that means that not working methods in inheritance, it is a bug. |
|
Parent class methods are referenced with the "super" keyword. This compiles and works. Is this considered inheritance?? public class parentclass
{
int x=128;
void p_method(string caller)
{
message( "p_method called from " + caller );
}
void parentclass()
{
}
void ~parentclass()
{
}
}
public class child extends parentclass
{
static parentclass parent; //null reference (optional)
void c_method()
{
super.p_method( "child" ); // call parent method with "super"
parent.p_method( "child" ); //(optional)
message("child says: super.x = " + super.x); //get parent var.
}
void child()
{
parent = super; //public reference to parentclass(optional)
}
void ~child()
{
}
}
extern void object::Inheritance() //--------------------------------Main-------------
{
child kid(); //new instance of child
kid.c_method(); //child method can access parent method
kid.parent.p_method( "extern" ); //parentclass by reference
} |
|
THERE IS A SUPER KEYWORD?! It doesn't even get highlighted by the editor. public class TestBase
{
int x = 1;
void TestBase()
{
message("TestBase constructor");
}
void testPrint()
{
message("x = "+x);
}
void testNoOverride(string s)
{
// This method of the base class is not overriden in the child class
message(s);
}
void testRecursion(int x)
{
message("TestBase::testRecursion called! THIS IS BAD"); // shouldn't get called
}
void testNoSuperCall()
{
message("parent, SHOULDN'T HAPPEN");
}
}
public class TestClass extends TestBase
{
int y = 2;
void TestClass()
{
super.TestBase();
message("TestClass constructor");
}
void testPrint()
{
super.testPrint();
message("y = "+y);
}
void testInsideCallNoOverride()
{
testNoOverride("testInsideCallNoOverride"); // without super.
}
void someOtherMethod()
{
super.testNoOverride("this is TestClass::someOtherMethod");
}
void testRecursion(int i)
{
if(i == 0)
{
message("Recursion works!");
return;
}
testRecursion(i-1);
}
void testNoSuperCall()
{
message("child");
}
}
extern void object::New()
{
TestClass test();
test.testPrint(); // works correctly
test.x = 2; // change base
test.y = 1; // change child
test.testPrint(); // works fine
test.testNoOverride("This should work"); // THIS DOESN'T WORK. Doesn't throw a compile error or anything, it just does nothing with executed
test.testInsideCallNoOverride(); // BROKEN, this is apparently also a no-op
test.someOtherMethod(); // works correctly
test.testRecursion(5); // this also works as expected (I was trying to relate this to issue #673)
test.testNoSuperCall(); // this also works fine
message("Finished without crashing!");
}In short - if you call a method from a base class that is not overriden in the child class, it will just do nothing. @Otaka A temporary workaround would be to add this to class B: public int baseMethod()
{
return super.baseMethod();
}Also, @MrSimbax, this needs to be documented in SatCom |
|
yes))) It works. Thank you very much. |
|
In reference to the no-ops: This is properly fixed with 5 lines of code in one place. (see next comment) results with krzys-h's test program: test.testPrint(); // still works
test.x = 2; // change base
test.y = 1; // change child
test.testPrint(); // still works
test.testNoOverride("This should work"); //output: "This should work" fixed.
test.testInsideCallNoOverride(); //output: "testInsideCallNoOverride" fixed.
test.someOtherMethod(); //output: "this is TestClass::someOtherMethod" still works
test.testRecursion(5); //output: "Recursion works!" still works
test.testNoSuperCall(); //output "child" CBot checks child first still works
message("Finished without crashing!");//<--this tooIt is also possible attach a public function to a class with " public class ClassA
{ }
public void ClassA::DoStuff() // can be overridden with DoStuff() { } inside the class
{ //must be public
message("this works too"); //unless the class overrides it.
}
extern void object::Test()
{
ClassA aClass();
aClass.DoStuff(); // output: "this works too"
}A few issues worth noting: Changing the class definition line after compiling it already, such as
It is possible to " It is possible to " It is possible to instantiate an array of classes with: classname myclass[];
myclass[0] = new classname();Radar outputs to an array of |
|
This code fixes inheritance: it goes between lines 368 and 369 in CBotClass.cpp current dev branch. if ( ret >= 0 ) return ret;
if ( m_pParent != nullptr )
{
ret = m_pParent->m_pCalls->DoCall(nIdent, name, pThis, ppParams, pResult, pStack, pToken);
if ( ret >= 0 ) return ret;
ret = m_pParent->m_pMethod->DoCall(nIdent, name, pThis, ppParams, pStack, pToken, m_pParent);
} |
|
@melex750 Thanks, I'll test this in a moment |
|
There are also keywords " protected static int a = 4;
|
|
In Java "final" for variables - it is "const" in c/c++ |
|
A fix for this issue: // CBotFunction.cpp between lines 1641 and 1642
if ( pOld != nullptr && pOld->m_pParent == nullptr )
{
pOld->m_pParent = CBotClass::Find( p->GetString() );
}
// and at the end of line 1643 same file, all current line numbers dev-branch
else if ( pOld != nullptr ) pOld->m_pParent = nullptr; |
|
I've just commited your changes with a few style fixes. I also fixed a possible bug when the base class could not be found (I just copied the error handling code from CBotClass::Compile1) |
Since when does CBot know how to cast class to string?!? I didn't know this even existed.
They can, and they should be allowed to. public class Grandparent
{
protected int x;
}
public class Parent extends Grandparent
{
}
public class Child extends Parent
{
public void Child()
{
this.x = 5;
message(this.x);
x = 3;
message(x);
// This syntax is terrible and counter-intuitive - super should work only for methods. Nevertheless, it works correctly.
super.x = 7;
message(super.x);
// This doesn't work - and there is no reason it should :P
//super.super.x = 8;
//message(super.super.x);
}
}
extern void object::TestGrandparent()
{
Child c = new Child();
}
That may be useful, but it breaks all the casting rules I'm aware of, so for me it's really counter-intuitive. :P ChildClass c = new BaseClass();
Your code is right, the CBot engine is wrong
And there is "private" too. public class SomeBaseClass
{
public int a_public;
protected int a_protected;
private int a_private;
public void SomeBaseClass(int a)
{
this.a_public = a;
this.a_protected = a;
this.a_private = a;
}
}
public class SomeClass extends SomeBaseClass
{
public void SomeClass(int a)
{
super.SomeBaseClass(a);
this.a_public = a+1;
this.a_protected = a+2;
this.a_private = a+3; // Shouldn't compile, but it does
super.a_private = 5; // This syntax makes no sense, but apparently also works (I would rather block using super to access variables at all)
}
public void test()
{
message("1: "+this.a_public);
message("2: "+this.a_protected);
message("3: "+this.a_private); // Shouldn't compile, but it does
}
}
extern void object::TestProtectionLevels()
{
SomeClass c = new SomeClass(0);
c.test();
message(c.a_public);
//message(c.a_protected); // This is correct - doesn't compile
//message(c.a_private); // This is correct - doesn't compile
}
It is highlighted indeed, but not implemented in the engine. I'll remove the highlighting in a moment so it doesn't confuse anyone. |
|
So what are you saying is, class inheritance almost works? I'm more than surprised. It's definitely something good, we'll have to document it. |
|
Thanks for the info. and excellent work. :) I thought extending object was ok because it's just an empty class of null pointers similar to point. |
|
Tested the build with new changes. All works fine except: I think we can close this ticket because now in general inheritance works, and create new bug with name "Child class cannot be casted to BaseClass reference" |
|
For documentation purposes: Remaining issues with inheritance: I also learned that parentClass constructors should be called before subClass constructors, About Polymorphism: All instances are created correctly but references like the following do not work properly. The code which handles inline instance declaration I have sorted most of this out already, new issue #683 ,I will post my findings soon. |
|
Guys did you say that everything is working now? And i can use class inheritance without troubles? What are limitations? Can i use static functions? I just tested inheritance works only for first case. public class class_2 extends class_1 - everything works. |
|
You've probably forgotten about the |
|
Done in #834 |
I have tested colobot version 0.1.5.0.
I thought that if cbot has classes, that means that should be inheritance of the classes, but I am not sure if it still in work or it is a bug, or I am doing something wrong because it does not documented.
I am trying the following code:
extern void object::New() {
B b=new B();
b.test();
}
public class A {
public int baseMethod(){
message("Base method");
return 2;
}
}
public class B extends A{
public void test(){
message("Child method");
int returnValue=baseMethod();
message("After baseMethod executing");
message("Return value "+returnValue);
}
}
The code is compiled without any errors but when it runs it shows the messages:
"Child method"
"After baseMethod executing"
"Variable not initialized"
Expected result:
"Child method"
"Base method"
"After baseMethod executing"
"Return value 2"
The text was updated successfully, but these errors were encountered: