Перенести приведение типов в производный класс?
-
12-09-2019 - |
Вопрос
Я заметил, что 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 тогда будет экземпляром наследующего класса, который знает это экземпляр наследующего класса?
Решение
Я разработал решение своей проблемы.Я новичок в сборке мусора 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;
}
=================================================================================
Надеюсь, это кому-нибудь поможет!
Другие советы
Я решил это, используя typemap и поле класса, которое содержит SWIG-структуру swig_type_info типа class.
Например.Предположим, у вас есть базовый класс, который содержит базовые функции связанного списка, но фактическими узлами может быть любой класс, производный от 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 typetabel еще не заполнен.