Приведение типа swig в производный класс?

Я заметил, что Swig предоставляет целый ряд функций, позволяющих приводить типы объектов к их родительским классам. Однако в C ++ можно создать такую ​​функцию:

A * getAnObject()
{
  if(someBoolean)
    return (A *) new B;
  else
    return (A *) new C;
}

Где «A» - родитель классов «B» и «C». Затем можно привести указатель, возвращаемый к типу «B» или «C», по своему усмотрению, например:

B * some_var = (B *) getAnObject();

Есть ли способ привести тип объекта, который я получил от функции создания универсального указателя, во время выполнения на языке сценариев с использованием оболочек? (В моем случае Lua?) У меня есть функция, которая может создавать один из примерно сотни возможных классов, и я бы хотел избежать написания огромной структуры переключателей, которую мне пришлось бы поддерживать на C ++. В момент, когда я получаю общий указатель, у меня также есть строковое представление типа данных, к которому я хотел бы его преобразовать.

Есть предположения? Спасибо!

-- РЕДАКТИРОВАТЬ --

Я заметил, что SWIG предлагает создавать конструкторы копирования для всех моих классов. Если бы он их сгенерировал, мог бы я сделать что-то вроде следующего ?:

var = myModule.getAnObject(); -- Function that returns an object type-cast down to a pointer of the parent class, as in the function getAnObject() above.
var = myModule.ClassThatExtendsBaseClass(var); -- A copy constructor that SWIG theoretically creates for me

и должен ли var быть экземпляром наследующего класса, который знает, что это экземпляр наследующего класса?


person zslayton    schedule 08.06.2009    source источник


Ответы (2)


Я разработал решение своей проблемы. Я новичок в сборке мусора lua, поэтому не уверен, что он защищен от утечки памяти, но он делает то, что мне нужно. (Это также небезопасно - если вы передадите допустимый тип данных и объект, который не должен быть приведен как этот тип данных, это приведет к плохому результату.)

=================================================================================

static int lua_typecast_Object_I(lua_State *L)
{
        void * myDataPtr;
        void ** ptrToPtr = &myDataPtr;

        // Attempt to convert the first parameter to a pointer of
        // the lowest parent type from which all other data types 
        // inherit. e.g. "Object_I"

        if (!SWIG_IsOK(SWIG_ConvertPtr(L, 1, ptrToPtr, SWIGTYPE_p_Namespace1__Object_I, 0)))
        {
                lua_pushnumber(L, -1);
                lua_pushstring(L,"Pointer conversion in typecast function failed.");
                return 2;
        }

        const char * type_name = luaL_checkstring(L, 2);

        // Search the SWIG module for a swig_type_info that contains the data
        // type string that was passed as the second parameter

        swig_module_info* module=SWIG_GetModule(L);
        swig_type_info *type = SWIG_TypeQueryModule(module,module,type_name);
        if(type == NULL)
        {
                lua_pushnumber(L, -2);
                lua_pushstring(L,"Failed to find swig_type_info for specified type.");
                return 2;
        }

        // Using the swig_type_info that we found, create a new object on 
        // the stack of the desired data type and return.

        SWIG_Lua_NewPointerObj(L, myDataPtr, type, 0);
        return 1;
}

=================================================================================

Надеюсь, это кому-то поможет!

person zslayton    schedule 18.06.2009
comment
Обычное соглашение Lua о возврате ошибок - это возвращать nil, сообщение, в котором вы возвращаете числовой код и сообщение. Возврат nil оказывается очень легко отличить от любого другого допустимого возвращаемого значения на стороне Lua, отсюда и идиома. Это также шаблон, которому следуют многие из основных модулей. В качестве альтернативы вы можете рассмотреть возможность использования luaL_error (), поскольку любая ошибка в именовании типов, вероятно, является серьезной проблемой. См. lua.org/manual/5.1/manual.html#luaL_error. для подробностей. - person RBerteig; 19.06.2009
comment
Я не замечаю никаких утечек, но не чувствую себя достаточно осведомленным во внутреннем устройстве SWIG, чтобы это подтвердить ;-) - person RBerteig; 19.06.2009

Я решил это, используя карту типов и поле класса, которое содержит SWIG-структуру swig_type_info типа класса.

Например. Предположим, у вас есть BaseClass, который содержит базовые функции связанного списка, но фактические узлы могут быть любым классом, производным от BaseClass. Таким образом, у вас есть полиморфный связанный список. В базовом классе я определяю значение «stored_swig_info», которое содержит результат вызова SWIG_TypeQuery (..). Я установил это значение при инициализации. Затем во время выполнения вы можете использовать следующее:

// The typemap converts a function result from C->Lua. 
%typemap(out) BaseClass* {
   // stored_swig_info is set by calling SWIG_TypeQuery("DerivedClass *"), done at
   // initialization, so it can be used here to read the actual type
   swig_type_info* info = $1->stored_swig_info;
   SWIG_NewPointerObj(L, $1, info, 0); SWIG_arg++;
};

// base class
class BaseClass {
private:
  swig_type_info *stored_swig_info;
public:
  BaseClass* next () { ... };
  BaseClass* prev () { ... };
};

// derived class
class DerivedClass: public BaseClass {
};

А в реальных модулях класса конструктор выполняет следующие действия:

BaseClass::BaseClass () {
  ...
  stored_swig_info = SWIG_TypeQuery("BaseClass *");
  ...
}

...

DerivedClass::DerivedClass () {
  ...
  stored_swig_info = SWIG_TypeQuery("DerivedClass *");
  ...
}

Замечание по реализации. Убедитесь, что эта инициализация вызывается после инициализации модуля lua, иначе метка типа SWIG еще не заполнена.

person xray    schedule 10.09.2014