Will it eventually be possible to do something like this:
Object obj(2);
or
Object *obj;
obj = new Object(2);
where either would call the constructor
Object::Object(int value)
{
...
return;
}
Or some variation, I realize it may not be the same, but will it be possible?
Are constructors implemented yet?
Right now Aurora only supports default class constructors (i.e.: a constructor with no arguments). To be able to support arguments, the first thing that Paul would need to do is modify the compiler to support method overloading; then support for passing arguments to constructors should be easy to implement. It's something that he's said that he's going to do, but I'm not sure where it falls on the list of priorities.
Oh, ok. I was wondering because I saw a constructor in the imgview example and they'd be useful to me :) Thanks for the clarification.
I don't know that it'd be particularly hard just to get overloading functions, but the problems arise with the current coersion where you can pass an integer variable where it expects a pointer and not get an error. Anything that can is automatically converted, and we'd lose a ton of that to have overloaded functions. Also there is currently no casting, except for the hackish *(sometype)(&x) which may or may not work since I haven't tried it, so you couldn't force it to call SomeFn(byte) instead of SomeFn(int) like you can in C++.
The solution, in my opinion, would be to add an "overload" keyword. For example:
class MyClass
{
ÂÃ, Ã‚Ã, declare overload MyFunction(int nParam);
ÂÃ, Ã‚Ã, declare overload MyFunction(int *pnParam);
ÂÃ, Ã‚Ã, declare overload MyFunction(byte nParam);
}
If you call a function that's been tagged as an 'overload' then the parameters have to match one of those signatures exactly and there's no type promotion performed. Without the keyword, then it's handled as it is now. It would allow for overloading, with backwards compatibility for existing code.
Edit: The one thing that Paul would have to implement to make this all work correctly would be typed pointers. Right now, every pointer is essentially treated as a void pointer. He'd need to add type checking so that this kind of thing would work:
class MyClass
{
declare overload MyFunction(MYSTRUCT1 *pStruct1);
declare overload MyFunction(MYSTRUCT2 *pStruct2);
}
With untyped pointers, there'd be no way for the compiler to know which function should be called, even with an overload keyword.
I've been working on my tutorial again and ran into an issue discussing Classes. My first example, "class1-0.src" works fine.
I then wrote "class1-1.src" and ran into trouble with my child class. It seemed to inherit o.k. but when I defined (redefined) a couple of methods, the new child methods were not called when I declared the child object. I had to create a new constructor for the child to get it all to work. This means the parent constructor and the child constructor are called/used. That can be a little costly in processing time if and when I ever get to coding my Matrix libraries.
( edit: I guess this is the way it has to be until Overloading Methods becomes possible )
Do I have to explicitly call the destructors?
I attached the .src and .exe files
// Dog.inc
// This include file provides the Dog Class
class Dog
{
def Tails, Legs as int;
def Color, Name, Ears as string;
declare Dog(); // Dog constructor
declare _Dog(); // Dog destructor
declare giveName( string somename );
declare growTail();
declare growLegs();
declare firColor();
declare growEars();
declare OutputToScreen();
}
Dog::Dog()
{
writeln("\nDog constructor has been called\n\n");
growTail();
growLegs();
growEars();
firColor();
return;
}
Dog::_Dog()
{
writeln("Dog destructor has been called\n\n");
return;
}
Dog::growTail()
{
writeln("Dog grows a tail\n");
Tails = 1;
return;
}
Dog::growLegs()
{
writeln("Dog grows legs\n");
Legs = 4;
return;
}
Dog::firColor()
{
writeln("Dog grows fir\n");
Color = "brown";
return;
}
Dog::giveName( somename as string )
{
writeln("your Dog is named\n");
Name = somename;
return;
}
Dog::growEars()
{
writeln("Dog grows ears\n");
Ears = "pointed";
return;
}
Dog::OutPutToScreen()
{
writeln ("\n\n");
writeln ("\n the name of my dog is " + Name);
writeln ("\n my dog has " + str$(Tails) + " tails");
writeln ("\n my dog has " + str$(Legs) + " legs");
writeln ("\n my dog's fir is " + Color);
writeln ("\n my dog has " + Ears + " ears");
writeln ("\n\n\n");
}
/* Dog.src - to be compiled as a console executable */
#include "Dog.inc"
global sub main
{
Dog Spot;
Spot.OutPutToScreen();
Spot._Dog();
writeln ("\npress any key\n");
while (GetKey() == "");
return;
}
/* BlackLabrador.src - to be compiled as a console executable */
#include "Dog.inc"
class BlackLabrador : Dog
{
declare BlackLabrador(); // BlackLabrador constructor
declare firColor();
declare growEars();
}
BlackLabrador::BlackLabrador()
{
writeln("\nBlackLabrador constructor has been called\n\n");
growEars();
firColor();
return;
}
BlackLabrador::firColor()
{
writeln("Black Labrador grows fir\n");
Color = "black";
return;
}
BlackLabrador::growEars()
{
writeln("Black Labrador grows ears\n");
Ears = "floppy";
return;
}
global sub main
{
Dog Spot;
Spot.giveName("Spot");
BlackLabrador Skippy;
Skippy.giveName("Skippy");
Spot.OutPutToScreen();
Skippy.OutPutToScreen();
Spot._Dog();
Skippy._Dog();
writeln ("\npress any key\n");
while (GetKey() == "");
return;
}
You forgot the VIRTUAL keyword. Only virtual methods are overridable.
You never explicitly call a constructor or destructor. That is handled by the compiler automatically.
thanks Paul
And if you want to see a destructor in action use NEW and DELETE to dynamically allocated the class.
When you define a class in main() the destructor is called when main ends. So you will not see output from a PRINT statement in the destructor.
global submain()
{
SomeClass class; //constructor (including base classes) called here
while getkey() = "";
} //destructor (including base classes) called here
If you use a pointer and NEW and DELETE you can see your test output
global submain()
{
Dog *spot = new(Dog,1); //constructor (including base classes) called here
delete dog; //destructor (including base classes) called here
while getkey() = "";
}
Thanks again Paul. When do you expect to be able to allow multiple layers of inheritance (BlackLab from Retriever from Dog)
I revamped the coding and renamed it MyDog.src. I editted my post to Larry at:
http://www.ionicwind.com/forums/index.php?topic=611.msg5397#msg5397
As a suggestion, when you declare class member variables, prefix them with "m_" to make it easy to distinguish in code that you're talking about the member of a class, and not a local variable. For example, I'd implement your class as:
class Dog
{
ÂÃ, int m_nTails;
ÂÃ, int m_nLegs;
ÂÃ, string m_strColor;
ÂÃ, string m_strName;
ÂÃ, string m_strEars;
ÂÃ, declareÂÃ, Dog();ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, // Dog constructor
ÂÃ, declare _Dog();ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, // Dog destructor
ÂÃ, declare giveName( string somename );
ÂÃ, declare growTail();
ÂÃ, declare growLegs();
ÂÃ, declare firColor();
ÂÃ, declare growEars();
ÂÃ, declare OutputToScreen();
}
The other suggestion is that instead of referencing the members directly, you create accessor methods:
CDog::GetLegs(), int
{
ÂÃ, Ã‚Ã, return m_nLegs;
}
CDog::SetLegs(int nLegs)
{
ÂÃ, Ã‚Ã, m_nLegs = nLegs;
}
What this allows you to do is improve the interface by performing checks on inputs, such as:
CDog::SetLegs(int nLegs), int
{
ÂÃ, Ã‚Ã, if (nLegs < 1 || nLegs > 4)
ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, return false;
ÂÃ, Ã‚Ã, m_nLegs = nLegs;
ÂÃ, Ã‚Ã, return true;
}
Finally, it allows you to transparently modify your code so that you can integrate new features and tie them to the accessor methods. For example, let's say that you wanted to add a flag if the dog has been injured. You add the member variable m_bInjured to the class and then can modify SetLegs() as:
CDog::SetLegs(int nLegs), int
{
ÂÃ, Ã‚Ã, if (nLegs < 1 || nLegs > 4)
ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, return false;
ÂÃ, Ã‚Ã, if (nLegs !=ÂÃ, 4)
ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, m_bInjured = true;
ÂÃ, Ã‚Ã, m_nLegs = nLegs;
ÂÃ, Ã‚Ã, return true;
}
CDog::IsInjured(), int
{
ÂÃ, Ã‚Ã, return m_bInjured;
}
Thanks MIke,
I will use your suggestions in my tutorial (I'm not a guru like you or Paul, so I would appreciate your input). My tutorial is going to introduce concepts to the OOP challenged (which I am one).
I was able create another example utilizing multiple inheritance ( Lab from Retriever from Dog ).