Jump to content
  • Advertisement
Sign in to follow this  
rck

Class Constructors

This topic is 4857 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

How can I prevent AngelScript from allowing the use of a class that has no default constructor without arguments? My class has a constructor with an argument (unsigned int).
result = engine->RegisterObjectBehaviour
(
	"Class",
	asBEHAVE_CONSTRUCT,
	"void f(uint val)",
	asFUNCTION(ConstructClass),
	asCALL_CDECL_OBJFIRST
);
Yet AngelScript still allows:
Class cls;
When only
Class cls(1);
Should work. Is there any way to enforce this? I thought of registering a constructor with no arguments, then throwing an error, but I would prefer this to be a build time error, not a runtime error.

Share this post


Link to post
Share on other sites
Advertisement
Hmm, I never thought about this case. There is currently no way to do what you want.

The biggest problem is that the compiler internally uses the default constructor to create temporary objects, e.g. when calling a function that returns an object of the type in a parameters. If you remove the possibility of using the default constructor (for example by raising an exception in the constructor), then it may cause problems that could be difficult to resolve.

I have to think about how to best solve this case. Unfortunately there is no immediately apparent solution.

For now I suggest you make the default constructor choose a default value for the parameter and initialize the object using that one, e.g. Class cls leads to Class(1) being called.



Share this post


Link to post
Share on other sites
WitchLord:
Do you plan to add support for non-default constructors in the future?

[Edited by - bozho on April 27, 2005 9:25:20 AM]

Share this post


Link to post
Share on other sites
WitchLord:
Just an idea about non-default constructors... My idea of an ideal solution would be something like this:

class A {
public:
A(int a, float b);
Construct(int a, float b);
};

A::A(int a, float b) {
...
}

A::Construct(int a, float b, A* instance) {
new(instance) A(a, b);
}

After that, register A::Construct as constructor for scripts, and AS compiler might translate lines like:

// script code
A a(1, 0.0);

into calls to A::Construct. Could this be done?

BTW, is it currently possible to register a class method as constructor for scripts? I've tried it, but it didn't work.

Share this post


Link to post
Share on other sites
Non-default constructors are already supported. Example:


// C++ code
void Construct(int param, object *o)
{
new(o) object(param);
}

engine->RegisterObjectBehaviour("object", asBEHAVE_CONSTRUCT, "void f(int)", asFUNCTION(Construct), asCALL_CDECL_OBJLAST);

// AngelScript code
object o(234);


You can register a method as a constructor (unless there is a bug), but it cannot be a virtual method, as part of the constructor's job is to initialize the virtual function table in the class.

Regards,
Andreas

Share this post


Link to post
Share on other sites
Which calling convention do I use? I've tried both asCALL_THISCALL and asCALL_CDECL_OBJLAST, but I get ESP error... Maybe I'm doing something wrong. I'll try it with a minimal example tomorrow.

Thanks for your help :)

Share this post


Link to post
Share on other sites
The calling convention depends on the function you register. A class method should be registered with asCALL_THISCALL calling convention. A global function acting as class method should be registered with asCALL_CDECL_OBJLAST or asCALL_CDECL_OBJFIRST.

The ESP problem can depend on calling convention, but can also depend on the function declaration you passed to the library.

Show me the functions implementation (at least it's parameters) and how you registered it and I might be able to tell you what's wrong.

Share this post


Link to post
Share on other sites
Ok... Here's the minimal code I'm using:

class Test2 {
public:
Test2(int a, int b);
virtual ~Test2();

void Constructor(int a, int b, Test2* instance);

public:
static void AngelScriptRegister(asIScriptEngine* pEngine);

public:
int m_nA;
int m_nB;
};

...

void Test2::Constructor(int a, int b, Test2* instance) {
new(instance) Test2(a, b);
}

I've tried to register Constructor as:
r = pEngine->RegisterObjectBehaviour(
"Test2",
asBEHAVE_CONSTRUCT,
"void Constructor(int a, int b)",
asMETHOD(Test2, Constructor),
asCALL_THISCALL);


Constructor is called, but I get ESP error. Then I tried:
r = pEngine->RegisterObjectBehaviour(
"Test2",
asBEHAVE_CONSTRUCT,
"void Constructor(int a, int b, Test2&in)",
asMETHOD(Test2, Constructor),
asCALL_THISCALL);

In this case, return code (r) is ok, but Constructor isn't called. Then I tried with handles (AddRef and Release are registered):
r = pEngine->RegisterObjectBehaviour(
"Test2",
asBEHAVE_CONSTRUCT,
"void Constructor(int a, int b, Test2@)",
asMETHOD(Test2, Constructor),
asCALL_THISCALL);

Again, Constructor is not called (return value r was ok)

Is there a combination I haven't tried? :)

Thnx

Share this post


Link to post
Share on other sites
Witchlord,

In the case of classes with no defualt constructors registered, why not simply treat it as a compilation error? That is, prevent the declaration of variables like:

Object myObject; // no params

As for static object assignment, aren't those catered for by the assignment operator and copy constructors with a default bitwise copy as a backup?

Maybe I'm missing something obvious here.. if so, please bear with me :)

Share this post


Link to post
Share on other sites
bozho:

Since you are registering the constructor as a class method, the object pointer will be available in the this pointer. It will not be passed as a parameter. Thus you ought to implement it like this:


class Test2 {
public:
Test2(int a, int b);
virtual ~Test2();

void Constructor(int a, int b);

public:
static void AngelScriptRegister(asIScriptEngine* pEngine);

public:
int m_nA;
int m_nB;
};

...

void Test2::Constructor(int a, int b) {
new(this) Test2(a, b);
}


The constructor should be registered as follows (your first option):


r = pEngine->RegisterObjectBehaviour(
"Test2",
asBEHAVE_CONSTRUCT,
"void Constructor(int a, int b)",
asMETHOD(Test2, Constructor),
asCALL_THISCALL);


This constructor will only be called if the script explicitly declares the object with the two parameters:


Test2 a(1,2); // Calls your constructor
Test2 b; // Calls the default constructor (which is not registered in the example above, causing an uninitialized object)


SharkBait:

There are times when AngelScript needs to be able to create a default object (implicitly) without copying another. When passing an object to a parameter marked as &out, is one such situation. Thus AngelScript will not work correctly if the default constructor isn't registered.

Of course, I could have the compiler make an error in this case, and it might even be the best thing to do. But then the application will have to register a default constructor for all objects it registers (unless it really shouldn't have one).

If the object type is registered with a size of zero, then the script cannot use any constructor to declare the object locally. It could be used to prevent the use of the default constructor, but then it would have to be manipulated through handles, and factory functions would be needed to create the objects and return their handles.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!