Сообщение Re: Циклические ссылки от 07.06.2016 17:20
Изменено 07.06.2016 17:24 GhostCoders
На данный момент генерируются враппер-классы, используемые по значению.
То есть для класса
использование будет в духе:
То есть доступ идет через точку.
И сам класс, по сути являющийся легким враппером, имеет семантику копирования.
Проблема возникает в случае если класс А использует класс Б и наоборот.
Обычно, в С++ используют forward declaration, реализацию выносят в отдельный .cpp файл (от .h заголовка),
и в заголовках используют указатель или ссылку.
Такие циклические связи между классами необходимо отразить и в моих врапперах.
Но! Forward declaration работает только для указателей или ссылок, а у меня значения!
Поэтому пришлось немного исхитриться.
Для простого аргумента используется:
и естественно, используется forward declaration для ClassB.
А для возвращаемых значений вот что:
где Circular::ClassBFwdPtr есть:
То есть для возращаемых значений их можно присвоить враппер классу (благодаря оператору приведения),
или сделать вызов на лету, с использованием ->
но получается, в одном месте используется стрелка, в другом точка. Нехорошо.
А как вам такая практика:
То есть можно использовать стрелку, даже для объектов-значений врапперов.
Есть ли подводные камни?
То есть для класса
class Printer
{
private:
void * printer_handle;
public:
Printer()
{
printer_handle = printer_create();
}
~Printer()
{
printer_destroy(printer_handler);
}
void Show()
{
printer_show(printer_handle);
}
};
использование будет в духе:
{
Printer printer_instance;
printer_instance.Show();
}
То есть доступ идет через точку.
И сам класс, по сути являющийся легким враппером, имеет семантику копирования.
Проблема возникает в случае если класс А использует класс Б и наоборот.
Обычно, в С++ используют forward declaration, реализацию выносят в отдельный .cpp файл (от .h заголовка),
и в заголовках используют указатель или ссылку.
Такие циклические связи между классами необходимо отразить и в моих врапперах.
Но! Forward declaration работает только для указателей или ссылок, а у меня значения!
Поэтому пришлось немного исхитриться.
Для простого аргумента используется:
void SetB(const Circular::ClassB& value)
{
struct raw_pointer_holder { void* raw_pointer; };
circular_classa_setb(mObject, reinterpret_cast<const raw_pointer_holder*>(&value)->raw_pointer);
}
и естественно, используется forward declaration для ClassB.
А для возвращаемых значений вот что:
Circular::ClassBFwdPtr GetB()
{
return Circular::ClassBFwdPtr(circular_classa_getb(mObject));
}
где Circular::ClassBFwdPtr есть:
namespace Circular
{
namespace beautiful_capi
{
template<typename WrappedObjType>
class forward_pointer_holder
{
void* m_pointer;
bool m_object_was_created;
public:
explicit forward_pointer_holder(void* pointer)
: m_object_was_created(false), m_pointer(pointer)
{
}
~forward_pointer_holder()
{
if (m_object_was_created)
{
reinterpret_cast<WrappedObjType*>(this)->~WrappedObjType();
}
}
operator WrappedObjType()
{
return WrappedObjType(m_pointer);
}
WrappedObjType* operator->()
{
m_object_was_created = true;
return new(this) WrappedObjType(m_pointer);
}
void* get_raw_pointer() const
{
return m_pointer;
}
};
}
class ClassA;
typedef beautiful_capi::forward_pointer_holder<ClassA> ClassAFwdPtr;
class ClassB;
typedef beautiful_capi::forward_pointer_holder<ClassB> ClassBFwdPtr;
}
То есть для возращаемых значений их можно присвоить враппер классу (благодаря оператору приведения),
или сделать вызов на лету, с использованием ->
Circular::ClassA a_object; ...
a_object.GetB()->Show(); // вызов на лету
Circular::ClassB b_object = a_object.GetB();
b_object.Show(); // а тут используем точку (".") как обычно
но получается, в одном месте используется стрелка, в другом точка. Нехорошо.
А как вам такая практика:
class Printer
{
private:
void * printer_handle;
public:
Printer()
{
printer_handle = printer_create();
}
~Printer()
{
printer_destroy(printer_handler);
}
Printer* operator->()
{
return this;
}
const Printer* operator->() const
{
return this;
}
void Show()
{
printer_show(printer_handle);
}
};
То есть можно использовать стрелку, даже для объектов-значений врапперов.
Есть ли подводные камни?
Re: Циклические ссылки
На данный момент генерируются враппер-классы, используемые по значению.
То есть для класса
использование будет в духе:
То есть доступ идет через точку.
И сам класс, по сути являющийся легким враппером, имеет семантику копирования.
Проблема возникает в случае если класс А использует класс Б и наоборот.
Обычно, в С++ используют forward declaration, реализацию выносят в отдельный .cpp файл (от .h заголовка),
и в заголовках используют указатель или ссылку.
Такие циклические связи между классами необходимо отразить и в моих врапперах.
Но! Forward declaration работает только для указателей или ссылок, а у меня значения!
Поэтому пришлось немного исхитриться.
Для простого аргумента используется:
и естественно, используется forward declaration для ClassB.
А для возвращаемых значений вот что:
где Circular::ClassBFwdPtr есть:
То есть для возращаемых значений их можно присвоить враппер классу (благодаря оператору приведения),
или сделать вызов на лету, с использованием ->
но получается, в одном месте используется стрелка, в другом точка. Нехорошо.
А как вам такая практика:
То есть можно использовать стрелку, даже для объектов-значений врапперов:
Есть ли подводные камни?
То есть для класса
class Printer
{
private:
void * printer_handle;
public:
Printer()
{
printer_handle = printer_create();
}
~Printer()
{
printer_destroy(printer_handler);
}
void Show()
{
printer_show(printer_handle);
}
};
использование будет в духе:
{
Printer printer_instance;
printer_instance.Show();
}
То есть доступ идет через точку.
И сам класс, по сути являющийся легким враппером, имеет семантику копирования.
Проблема возникает в случае если класс А использует класс Б и наоборот.
Обычно, в С++ используют forward declaration, реализацию выносят в отдельный .cpp файл (от .h заголовка),
и в заголовках используют указатель или ссылку.
Такие циклические связи между классами необходимо отразить и в моих врапперах.
Но! Forward declaration работает только для указателей или ссылок, а у меня значения!
Поэтому пришлось немного исхитриться.
Для простого аргумента используется:
void SetB(const Circular::ClassB& value)
{
struct raw_pointer_holder { void* raw_pointer; };
circular_classa_setb(mObject, reinterpret_cast<const raw_pointer_holder*>(&value)->raw_pointer);
}
и естественно, используется forward declaration для ClassB.
А для возвращаемых значений вот что:
Circular::ClassBFwdPtr GetB()
{
return Circular::ClassBFwdPtr(circular_classa_getb(mObject));
}
где Circular::ClassBFwdPtr есть:
namespace Circular
{
namespace beautiful_capi
{
template<typename WrappedObjType>
class forward_pointer_holder
{
void* m_pointer;
bool m_object_was_created;
public:
explicit forward_pointer_holder(void* pointer)
: m_object_was_created(false), m_pointer(pointer)
{
}
~forward_pointer_holder()
{
if (m_object_was_created)
{
reinterpret_cast<WrappedObjType*>(this)->~WrappedObjType();
}
}
operator WrappedObjType()
{
return WrappedObjType(m_pointer);
}
WrappedObjType* operator->()
{
m_object_was_created = true;
return new(this) WrappedObjType(m_pointer);
}
void* get_raw_pointer() const
{
return m_pointer;
}
};
}
class ClassA;
typedef beautiful_capi::forward_pointer_holder<ClassA> ClassAFwdPtr;
class ClassB;
typedef beautiful_capi::forward_pointer_holder<ClassB> ClassBFwdPtr;
}
То есть для возращаемых значений их можно присвоить враппер классу (благодаря оператору приведения),
или сделать вызов на лету, с использованием ->
Circular::ClassA a_object; ...
a_object.GetB()->Show(); // вызов на лету
Circular::ClassB b_object = a_object.GetB();
b_object.Show(); // а тут используем точку (".") как обычно
но получается, в одном месте используется стрелка, в другом точка. Нехорошо.
А как вам такая практика:
class Printer
{
private:
void * printer_handle;
public:
Printer()
{
printer_handle = printer_create();
}
~Printer()
{
printer_destroy(printer_handler);
}
Printer* operator->()
{
return this;
}
const Printer* operator->() const
{
return this;
}
void Show()
{
printer_show(printer_handle);
}
};
То есть можно использовать стрелку, даже для объектов-значений врапперов:
{
Printer printer_instance;
printer_instance->Show();
}
Есть ли подводные камни?