#include #include #include #include #include //A basic derived GInterface, just to test Glib::Interface G_DECLARE_INTERFACE (TestIface, test_Iface, TEST, IFACE, GObject) struct _TestIface { GTypeInterface g_iface; }; static void test_Iface_init (gpointer) {} GType test_Iface_get_type (void) { static GType type = 0; if (!type) { const GTypeInfo info = { sizeof (TestIface), // class_size test_Iface_init, // base_init nullptr, // base_finalize nullptr, // class_init nullptr, // class_finalize nullptr, // class_data 0, // instance_size 0, // n_preallocs nullptr, // instance_init nullptr // value_table }; type = g_type_register_static (G_TYPE_INTERFACE, "TestIface", &info, GTypeFlags(0)); } return type; } #define TEST_TYPE_IFACE (test_Iface_get_type ()) //A basic derived GObject, just to test Glib::Object. typedef struct { GObject parent; } TestDerived; typedef struct { GObjectClass parent; } TestDerivedClass; #define TEST_TYPE_DERIVED (test_derived_get_type ()) #define TEST_DERIVED(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_DERIVED, TestDerived)) #define TEST_DERIVED_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST ((cls), TEST_TYPE_DERIVED, TestDerivedClass)) #define TEST_DERIVED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_DERIVED, TestDerivedClass)) static void test_derived_class_init (TestDerivedClass *) {} static void test_derived_init (TestDerived *) {} G_DEFINE_TYPE_EXTENDED(TestDerived, test_derived, G_TYPE_OBJECT, 0, G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE, test_Iface_init)) class TestInterface; class TestInterface_Class : public Glib::Interface_Class { public: typedef TestInterface BaseClassType; friend class TestInterface; const Glib::Interface_Class& init() { if(!gtype_) // create the GType if necessary { // Glib::Interface_Class has to know the interface init function // in order to add interfaces to implementing types. class_init_func_ = &TestInterface_Class::iface_init_function; // We can not derive from another interface, and it is not necessary anyway. gtype_ = test_Iface_get_type(); } return *this; } static void iface_init_function(void* /* g_iface */, void* /* iface_data */) { } //static Glib::ObjectBase* wrap_new(GObject*); }; class TestInterface : public Glib::Interface { protected: typedef TestInterface_Class CppClassType; TestInterface() : Glib::Interface(derived_interface_class_.init()) {} public: //A real application would never make the constructor public. //It would instead have a protected constructor and a public create() method. TestInterface(GObject* gobject, int i) : Glib::Interface(gobject), i_(i) { } static void add_interface(GType gtype_implementer) { derived_interface_class_.init().add_interface(gtype_implementer); } TestInterface(const TestInterface& src) = delete; TestInterface& operator=(const TestInterface& src) = delete; TestInterface(TestInterface&& src) noexcept : Glib::Interface(std::move(src)), i_(std::move(src.i_)) {} TestInterface& operator=(TestInterface&& src) noexcept { Glib::Interface::operator=(std::move(src)); i_ = std::move(src.i_); return *this; } int i_; private: friend class TestInterface_Class; static CppClassType derived_interface_class_; }; class DerivedObject_Class : public Glib::Class { public: typedef GObjectClass BaseClassType; typedef Glib::Object_Class CppClassParent; static void class_init_function(void* g_class, void* class_data) { const auto klass = static_cast(g_class); CppClassParent::class_init_function(klass, class_data); } const Glib::Class& init() { if(!gtype_) // create the GType if necessary { // Glib::Class has to know the class init function to clone custom types. class_init_func_ = &DerivedObject_Class::class_init_function; // This is actually just optimized away, apparently with no harm. // Make sure that the parent type has been created. //CppClassParent::CppObjectType::get_type(); // Create the wrapper type, with the same class/instance size as the base type. register_derived_type(test_derived_get_type()); // Add derived versions of interfaces, if the C type implements any interfaces: TestInterface::add_interface(get_type()); } return *this; } }; TestInterface::CppClassType TestInterface::derived_interface_class_; // initialize static member class DerivedObject : public Glib::Object, public TestInterface { public: typedef DerivedObject_Class CppClassType; //A real application would never make the constructor public. //It would instead have a protected constructor and a public create() method. DerivedObject(int i) : Glib::ObjectBase(nullptr), Glib::Object(Glib::ConstructParams(derived_object_class_.init())), i_(i) { } DerivedObject(const DerivedObject& src) = delete; DerivedObject& operator=(const DerivedObject& src) = delete; DerivedObject(DerivedObject&& src) noexcept : Glib::Object(std::move(src)), TestInterface(std::move(src)), i_(std::move(src.i_)) {} DerivedObject& operator=(DerivedObject&& src) noexcept { Glib::Object::operator=(std::move(src)); TestInterface::operator=(std::move(src)); i_ = std::move(src.i_); return *this; } int i_; private: friend class DerivedObject_Class; static CppClassType derived_object_class_; }; DerivedObject::CppClassType DerivedObject::derived_object_class_; // initialize static member /* Shouldn't this work too? * No, because Glib::Interface::Interface(Interface&& src) does not call * Glib::ObjectBase::initialize_move(), and Glib::Interface::operator=(Interface&& src) * does not call Glib::ObjectBase::operator=(std::move(src)). static void test_interface_move_constructor() { GObject *gobject = G_OBJECT(g_object_new(TEST_TYPE_DERIVED, nullptr)); g_object_ref(gobject); TestInterface derived(gobject, 5); std::cout << "debug: gobj(): " << derived.gobj() << std::endl; g_assert(derived.gobj() == gobject); TestInterface derived2(std::move(derived)); g_assert_cmpint(derived2.i_, ==, 5); std::cout << "debug: gobj(): " << derived2.gobj() << std::endl; g_assert(derived2.gobj() == gobject); } static void test_interface_move_assignment_operator() { GObject *gobject = G_OBJECT(g_object_new(TEST_TYPE_DERIVED, nullptr)); g_object_ref(gobject); TestInterface derived(gobject, 5); //std::cout << "debug: gobj(): " << derived.gobj() << std::endl; g_assert(derived.gobj() == gobject); TestInterface derived2 = std::move(derived); g_assert_cmpint(derived2.i_, ==, 5); //std::cout << "debug: gobj(): " << derived2.gobj() << std::endl; g_assert(derived2.gobj() == gobject); } */ static void test_object_with_interface_move_constructor() { DerivedObject derived(5); g_assert_cmpint(derived.i_, ==, 5); GObject* gobject = derived.gobj(); g_assert(derived.gobj() == gobject); DerivedObject derived2(std::move(derived)); g_assert_cmpint(derived2.i_, ==, 5); g_assert(derived2.gobj() == gobject); g_assert(derived.gobj() == nullptr); } static void test_object_with_interface_move_assignment_operator() { DerivedObject derived(5); g_assert_cmpint(derived.i_, ==, 5); GObject* gobject = derived.gobj(); g_assert(derived.gobj() == gobject); DerivedObject derived2(6); derived2 = std::move(derived); g_assert_cmpint(derived2.i_, ==, 5); g_assert(derived2.gobj() == gobject); g_assert(derived.gobj() == nullptr); } int main(int, char**) { Glib::init(); //test_interface_move_constructor(); //test_interface_move_assignment_operator(); test_object_with_interface_move_constructor(); test_object_with_interface_move_assignment_operator(); return EXIT_SUCCESS; }