Я хотел бы недавно описать ситуацию, с которой я столкнулся, чтобы задать вопрос в каком-то контексте.
Я пишу оболочку Python C++. Базовым элементом Python является PyObject. Каждый объект в Python представляет собой PyObject + более необязательный материал.
То есть, первый sizeofPyObject)
байты гарантированно заполняют поля PyObject, но различные объекты могут выделять дополнительную непрерывную память.
Выгода (причина?) Для этого заключается в том, что все может быть возвращено в PyObject
.
Я пытаюсь обернуть такого зверя:
class CxxWrapper : PyObject {}
Скажем, я создаю void foo(PyObject* p)
и вставляю foo
в одну из таблиц функций-указателей времени исполнения Python.
Тогда среда выполнения вызовет эту функцию (по какой-либо причине), передав указатель на соответствующий PyObject
.
Я хотел бы иметь возможность придать этот результат прямо к соответствующему объекту CxxWrapper:
CxxWrapper* cxxw = static_cast<CxxWrapper>p;
Однако я не вижу никакого способа заставить этот механизм работать. Потому что я не вижу способа установить базовый объект в какой-то PyObjectPlusExtra
.
Есть какой-либо способ сделать это? А если нет, то каково ограничение C++?
Плохо сформировавшийся вопрос. С 20:20 задним числом, вот что происходит:
Я имею дело с C Library использует схему наследования типа C, т.е.
struct CBase{
int a,b;
}
struct CDer{
CBase ab;
int c;
}
Я планирую свой C++ код таким образом:
class CxxBase : CBase
Так что, если я получаю указатель от C, я могу привести к эквивалентному объекту CxxBase и наоборот.
Проблема в том, что C++ управляет наследованием в значительной степени аналогично тому, как это показано на примере C. Финал: Der: Base будет хранить базу, а затем Der, а затем конечный объект в смежной памяти.
Таким образом, невозможно выполнить этот союз. И CDer, и CxxDer будут неизвестного размера.
Требуется другой метод, например, предложение Барри.
Тем не менее, это связано с достаточно дорогостоящим поиском.
Я не вижу решения лучше, чем существующее в проекте, над которым я работаю:
struct Bridge {
CObj cob;
CxxObj* p_cxxob;
}
const CxxObj& to_cxx(CObj* cob) { return *(cob->p_cxxob); }
Это неправильный способ сделать это, поскольку вы никогда не сможете построить свой объект! Вместо этого вы можете определить карту между PyObject
и вашими объектами:
std::unordered_map<PyObject*, CxxStff> stuff;
void foo(PyObject* o) {
CxxStuff& extra = stuff[o];
// etc
}
Поместите все, что захотите, в этот дополнительный класс, и вам будет хорошо.
CxxWrapper* cxxw = static_cast<CxxWrapper*>(p);