Оглавление

Регистрация иерархий класса

AngelScript автоматически не определяет связей между зарегистрированными классами, поэтому необходимо это сделать вручную перед регистрацией объектов.

На данный момент иерархии могут быть зарегистрированны только для ссылочных типов, не для типов-значений.

Регистрация отношений

AngelScript предоставляет нам 2 метода регистрации отношений классов - asBEHAVE_REF_CAST и asBEHAVE_IMPLICIT_REF_CAST. asBEHAVE_REF_CAST позволяет приводить типы только через оператор приведения. asBEHAVE_IMPLICIT_REF_CAST стоит использовать если вы хотите, чтобы компилятор выполнял приведения типов неявно по мере необходимости.

Обычно используется asBEHAVE_IMPLICIT_REF_CAST для приведения типа от наследованного к базовому, а asBEHAVE_REF_CAST - от базового к наследуемому.

// Пример REF_CAST
template<class A, strong>
B* refCast(A* a)
{
    // Если хенлд нулевой, то просто вернем его
    if( !a ) return 0;

    // Пытаемся динамически привести указатель к желаемому типу
    B* b = dynamic_cast<B*>(a);
    if( b != 0 )
    {
        // После приведения увеличим счетчик ссылок для возвращаемого хендла
        b->addref();
    }
    return b;
}

// Пример регистрации
r = engine->RegisterObjectBehaviour("base", asBEHAVE_REF_CAST, "derived@ f()", asFUNCTION((refCast)), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("derived", asBEHAVE_IMPLICIT_REF_CAST, "base@ f()", asFUNCTION((refCast)), asCALL_CDECL_OBJLAST); assert( r >= 0 );

Заметим, что может быть необходимо добавить дополнительные скобки к макросу asFUNCTION чтобы препроцессор не интерпретировал , в шаблоне как разделитель аргументов.

Помните, что скрипт спокойно реагирует на нулевые указатели, в этом случае результат также будет нулевой. Это значит что приведение типов не должно быть представлено виртуальным методом класса, потому что вызов приведет к ошибке в случае нулевого указателя.

Наследование свойств и методов

Аналогично отношениям, методы и свойства не определяются автоматически. Поэтому необходимо вручную зарегистрировать все необходимые методы и свойства для наследуемых классов, дублирования кода вы можете избежать немного подумав ;) Ниже представлен пример регистрации методов и свойст для базового и наследуемого классов (регистрация отношений опущена для кораткости):
// Базовый класс
class base
{
public:
  virtual void aMethod();
  
  int aProperty;
};

// Наследуемый класс
class derived : public base
{
public:
  virtual void aNewMethod();
  
  int aNewProperty;
};

// Регистрация представлена шаблоном, с поддержкой множественного наследования
template <class T>
void RegisterBaseMembers(asIScriptEngine *engine, const char *type)
{
  int r;

  r = engine->RegisterObjectMethod(type, "void aMethod()", asMETHOD(T, aMethod), asCALL_THISCALL); assert( r >= 0 );
  
  r = engine->RegisterObjectProperty(type, "int aProperty", offsetof(T, aProperty)); assert( r >= 0 );
}

template <class T>
void RegisterDerivedMembers(asIScriptEngine *engine, const char *type)
{
  int r;

  // Наследуемые классы регистрируем вызовом регистрации базового класса
  RegisterBaseMembers(engine, type);

  // Регистрируем новые члены
  r = engine->RegisterObjectMethod(type, "void aNewMethod()", asMETHOD(T, aNewMethod), asCALL_THISCALL); assert( r >= 0 );

  r = engine->RegisterObjectProperty(type, "int aProperty", offsetof(T, aProperty)); assert( r >= 0 );
}

void RegisterTypes(asIScriptEngine *engine)
{
  int r;

  // Регистрируем базовый тип
  r = engine->RegisterObjectType("base", 0, asOBJ_REF); assert( r >= 0 );
  RegisterBaseMembers(engine, "base");

  // Регистрируем наследуемый тип
  r = engine->RegisterObjectType("derived", 0, asOBJ_REF); assert( r >= 0 );
  RegisterDerivedMembers(engine, "derived");
}

Перевод - arroy.one@gmail.com. При копировании материалов указывайте ссылку на источник.