Advertisement

Is there a way to define an interface and its implementation inside application code

Started by June 15, 2021 09:56 AM
2 comments, last by eao197 3 years, 5 months ago

Hi!

I'm trying to figure out how to implement an interface and its implementation inside the application code. I want to have an interface App like:

interface App {
	void Foo();
	void Bar();
};

A user has to write a script with Init function inside that accepts a reference to App:

// Somewhere in user code.
void Init(App @ app) {
  if(some_condition) app.Bar();
  if(another_condition) app.Foo();
  ...
}

I need the interface App to hide the detail of the actual implementation of the interface between the application and the user-provided script. It means that there is something like:

namespace appdetails {
	class ActualApp : App {
		void Foo() override {...}
		void Bar() override {...}
		...
	};
	void CallInit(ActualApp @ app) {
		::Init(app); // Init() is provided by user.
	}
}

I don't want to describe App and appdetails::ActualApp in script files. I want to define them in the application code. Something like:

engine->RegisterInterface("App", ...);
engine->RegisterInterfaceMethod("App", "void Foo()");
engine->RegisterInterfaceMethod("App", "void Bar()");
...
engine->SetDefaultNamespace("appdetails");
engine->RegisterObjectType("ActualApp", 0, asOBJ_REF);
engine->RegisterObjectBehaviour("ActualApp", asBEHAVE_ADDREF, ...);
engine->RegisterObjectBehaviour("ActualApp", asBEHAVE_RELEASE, ...);
engine->RegisterObjectMethod("ActualApp", "void Foo()");
engine->RegisterObjectMethod("ActualApp", "void Bar()");

But I don't see any way of telling the engine that ActualApp implements App interface.

The only method I've found in the doc is to implement opImplCast for ActualApp type. Something like:

class App {
public:
	virtual ~App();
	int AddRef();
	int Release();
	virtual void Foo() = 0;
	virtual void Bar() = 0;
	...
};
class ActualApp : public App {
	void Foo() override {...}
	void Bar() override {...}
	static App * castToApp(ActualApp * obj) {
		App * result = obj;
		result->AddRef();
		return result;
	}
};
...
engine->SetDefaultNamespace("appdetails");
engine->RegisterObjectType("ActualApp", 0, asOBJ_REF);
...
engine->RegisterObjectMethod("ActualApp", "App @ opImplCast()",
		asFUNCTION(ActualApp::castToApp), asCALL_CDECL_OBJLAST);

But in that case, I get an application crash somewhere inside as_scriptengine.cpp source code. I suppose it's because AngelScript expects that the opImplCast returns an object derived from asIScriptObject, but that isn't my case.

So I decided that there is no way to define an interface and its implementation in the application code. I'm right? Or there is some way to do that?

RegisterInterface registers a script interface, not a C++ interface. This would be used when you want to establish the interface that a script must implement so that the application can interact with the script object without having to know the actual script implementation.

You should register the C++ interface using RegisterObjectType without the factory behaviour since it shouldn't be possible to create an instance of the interface. Then you can register the C++ class hierarchy with the opCast and opImplCast methods as you already figured out.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement

@WitchLord thanks!

This topic is closed to new replies.

Advertisement