Re: (glibmm) Deeper level of inheritance in own type of objects - how-to or plans to implement?
- From: "Cristi P" <cristi posoiu gmail com>
- To: "Armin Burgmeier" <armin arbur net>, gtkmm-list gnome org
- Subject: Re: (glibmm) Deeper level of inheritance in own type of objects - how-to or plans to implement?
- Date: Mon, 1 Dec 2008 23:22:00 +0200
Attached, a C++ program. Compile instruction at beginning. Comments about expected results/problems, in it as well.
First run - uncomment test_5() call in main(). 2nd run, comment it back.
I hope it makes my rant somewhat clearer.
Cristi
On Wed, Nov 26, 2008 at 1:06 PM, Armin Burgmeier
<armin arbur net> wrote:
On Wed, 2008-11-26 at 03:00 +0200, Cristi P wrote:
> I struggled some time ago with doing object inheritance at more than
> one level, like:
> Glib::Object -> MyObjectA (w/ some properties for example) ->
> MyObjectB (w/ additional properties and/or overriden [virtual]
> functions)
> While the gtkmm says about using "inheritance" I couldn't solve the
> problem the way I expect from a C++ library. So, unless I'm mistaken
> somewhere, it *almost* is impossible.
> At that time I did some hard stuff to overcome that problem (with
> implications on how you write your objects) but now I'm getting in
> even bigger problems, when
> instead of starting from Glib::Object I start from some other C++
> wrapper, like, for example,
> Clutter::Group -> MyObjectA -> MyObjectB
>
> This is really annoying since I want to use C++ w/ the various
> wrappers in more then a simplistic GUI wrapper and with one level of
> inheritance :-(
>
> So far the problems that I think I saw:
> a) it seems that the glibmm::object* source files (or at least some
> ObjectBase constructors) are assuming derived objects are mostly C++
> wrappers or one level deeper
> b) (from memory) saw some strange things about declaring the wrapper's
> type as being the C actual type instead of the just created type ?
> I think there was also a comment like "allow g_peek_class..." to
> work !?
> c) wrappers around methods want to "peek" at the original C object to
> call some functions for example, and are assuming current object has
> its parent type the C object, which, in case it runs on
> object MyObjectB, it is a wrong assumption.
I don't really understand what your problem is. Could you be more
specific on what the actual problem is when you have a Glib::Object -> A
-> B inheritance tree? And maybe provide a compilable test case?
Maybe you need to create an own GType for each of your derived classes.
This can be accomplished by calling the Glib::ObjectBase constructor
with the type name as a string. But this is only a guess.
> Can't the wrapping code gkmmproc is building, try, since it really
> knows (or could) the C type, work directly on that type (w/
> g_peek_class...) instead of relying on the
> actual object instance type being derived directly from the C type?
> d) I also saw some comments about skiping some virtual function calls.
> I wonder:
> 1) what's the optimization they're talking about? (haven't
> checked sources enough)
When a C++ wrapper is created, such as Gtk::Window, and a C virtual
function is called on the underlying GObject, such as the default signal
handler for the "show" signal, then we can skip calling the virtual
on_show() member function of the C++ object, because it cannot be
overriden anyway.
However, if the same (C) virtual function is called on an instance of a
derived class, such as ExampleWindow inheriting from Gtk::Window, then
ExampleWindow could have overriden the on_show() (C++) virtual function,
so we need to call it.
> 2) (would have to check) - can they also be a source of problems
> for the thing I want to have fixed?
I don't think so.
> Anyway, I might be mistaken, and if there is a method to accomplish
> what I said in the beginning that I want, I'd be glad to hear it!
>
> Thanks.
Armin
#include <glibmm.h>
#include <gtkmm.h>
// to compile:
// g++ -g `pkg-config --cflags glibmm-2.4 gtkmm-2.4` `pkg-config --libs glibmm-2.4 gtkmm-2.4` demo.cpp
// ====== Some utility functions
static void print_type(const GType ot)
{
GType opt = g_type_parent(ot);
printf("type=%d(%s) baseType=%d(%s)",
(int)ot, g_type_name(ot), (int)opt, g_type_name(opt));
}
static void print_object(const Glib::Object& o, const char *ending = "\n")
{
GType ot = G_OBJECT_TYPE(o.gobj());
printf("object: %p, ", o.gobj());
print_type(ot);
printf("%s", ending);
}
static void print_prop(const Glib::Object& o, const char* n)
{
GParamSpec* param_spec = g_object_class_find_property(G_OBJECT_GET_CLASS(o.gobj()), n);
print_object(o, "");
printf(" property: %s found=%s\n", n, (param_spec? "yes":"false"));
// SEEME: unref the param_spec?
}
// ==============
struct Object1: public Glib::Object
{
Object1()
{
}
};
struct Object2: public Glib::Object
{
Object2()
{
}
};
void test_1()
{
printf("=== test 1\n");
Object1 o1;
Object2 o2;
print_object(o1);
print_object(o2);
/*
Somewhat expected results were to have the types of these 2 be different (automatically registered) and parent type to be GOBject.
But let's say it is ok and continue...
Well, almost, I don't understand why it is not ok to have them at least declared as gtkmm_Object
*/
}
// =================================
struct Object2_1: public Glib::Object
{
Object2_1():
ObjectBase("Object2_1") //as per docs, this seems the way to create a new type.
{
}
};
struct Object2_2: public Glib::Object
{
Object2_2():
ObjectBase("Object2_2")
{
}
};
void test_2()
{
printf("=== test 2\n");
Object2_1 o1;
print_object(o1);
Object2_2 o2;
print_object(o2);
/*
Expected results, it is ok, let's continue/.
Well, almost, I don't understand why it is not ok to have base_type be gtkmm_Object and code insist on getting over that.
*/
}
// ===============================
struct Object3_1: public Glib::Object
{
Object3_1():
ObjectBase("Object3_1") //as per docs, this seems the way to create a new type.
, prop(*this, "prop1")
{
}
Glib::Property<gint32> prop;
};
struct Object3_2: public Glib::Object
{
Object3_2():
ObjectBase("Object3_2")
, prop(*this, "prop2")
{
}
Glib::Property<gint32> prop;
};
void test_3()
{
printf("=== test 3\n");
Object3_1 o1;
print_prop(o1, "prop1");
print_prop(o1, "prop2");
Object3_2 o2;
print_prop(o2, "prop1");
print_prop(o2, "prop2");
/*
Expected results (besides comments from previous test), let's continue/
*/
}
// ================
struct Object4: public Object3_1
{
Object4()
: ObjectBase("Object4")
{
}
};
void test_4()
{
printf("=== test 4\n");
Object3_1 o1;
print_prop(o1, "prop1");
print_prop(o1, "prop2");
Object4 o4;
print_prop(o4, "prop1");
print_prop(o4, "prop2");
/*
BAD... Object4 is still declared as deriving from Object (it is a similar class to Object3_1, to C and C++ glib :-( )
Checking the code, I think the following areas are having some problems:
- register_derived_type - since it takes the type name as the base type name prefixed by "Gtkmm_", it
seems that the correct name should be: "register_cpp_wrapper_type" ?
- and in object*.* files it is called w/ base type always being G_OBJECT anyway?
- Object() constructor - you can override the type to not be G_OBJECT_TYPE only if you setup a custom type name, which is ok,
but, then, why call a "clone_custom_type" to get this object's type? When it is supposed to be already created and
given by its own ObjectClass data member?
- and, bad, we clone from the G_OBJECT_TYPE, due to the ObjectClass::init() call first
- I can guess this constructor should be only for C++ objects derived only from G_OBJECT?
- checking into glibmm and gtkmm - couldn't find a call to it
- clone_custom_type:
- see above: "why *clone*"?
- Q: if your program said you want a specific type_name, then WHY we *clone* that type?
- it does a very bad assumption: that you're deriving your object directly from a wrapper, and as such
it takes as your parent type one type above the level you'd want.
While it might be ok for objects derived immediately from a wrapper, it will deny an inheritance
tree bigger than that (it won't correctly declare your real parent class, but take one from a level above)
- how to fix: 2 sugestions:
-a) Don't care about getting rid of the C++ wrapper types from the chain. so... use directly gtype_
-b) make somehow the OBjectClass know this *current* object and only this one (no derived ones) know about it being a c++ wrapper
(I think that all C++ direct wrappers are instantiated w/ custom_type_name = 0, maybe you could use that, else, buildup
some other ObjectBase constructor w/ an additional "is_wrapper" parameter?)
Note that knowing if the object is a C++ wrapper could have more benefits!
Other comments:
- look how hard also the inheritance problem is handled in the wrappers - lot of fidling with *both* the ObjectClass and the various
constructors and the get_type/get_base_type overloaded functions :-(
- in order for virtual functions of your derived objects to work, it looks like you have to have setup a custom_name to your class so that
the is_derived_() returns true (see, for example, why, by looking at virtual Widget::on_button_pressed_event(...)
- but in the same time, if you give it a real custom_name that is not the anonymous name, then you're going to actually
have created a *clone* of your actual object type - see Object::Object() and OBject::Object(ConstructParams)
Probably, by looking at code and current gtk wrappers, to allow you to have inheritance down in the C glib
way for your own class tree, you'd have to define:
- your own OBjectClass
- your own get_type and get_base_type static functions
- both simple constructor and Constructor(Glib::ConstructorParams)
*/
}
// ================
struct MyLabel: public Gtk::Label
{
MyLabel()
: Gtk::Label(),
property_automatic_space_strip(*this, "automatic-space-strip")
{
}
Glib::Property<gint32> property_automatic_space_strip;
};
void test_5()
{
printf("=== test 5\n");
MyLabel l;
print_object(l);
l.set_text("blah");
/*
You're going to get:
(process:24006): GLib-GObject-CRITICAL **: g_object_class_install_property: assertion `class->set_property != NULL' failed
I guess you have to do something else to obtain the desired effect of having a new GType for this class and be able to add properties)
*/
}
// ==================
struct MyLabel2: public Gtk::Label
{
MyLabel2()
:
Glib::ObjectBase("MyLabel2"),
Gtk::Label(),
property_automatic_space_strip(*this, "automatic-space-strip")
{
property_automatic_space_strip.set_value(1);
}
Glib::Property<gint32> property_automatic_space_strip;
};
struct MyLabel3: public MyLabel2
{
MyLabel3()
:
Glib::ObjectBase("MyLabel3"),
MyLabel2(),
property_2(*this, "prop2")
{
property_2.set_value(1);
}
Glib::Property<gint32> property_2;
};
void test_6()
{
printf("=== test 6\n");
MyLabel2 l2;
print_object(l2);
l2.set_text("blah");
print_prop(l2, "prop2");
MyLabel3 l3;
print_object(l3);
l3.set_text("blah");
l3.property_automatic_space_strip.set_value(10); // works ok
print_prop(l3, "automatic-space-strip");
/*
Type of MyLabel2 - ok (except for not wanting to use gtkmm_Label.
type of MyLabel3 - WRONG :-(
And because of that, you'd somehow expect, since the types are identical, to not have l3.prop_2 present (unless you
consider these 2 new properties to be "dynamic" properties - which they aren't)
*/
}
// ================
int main()
{
Glib::init();
test_1();
test_2();
test_3();
test_4();
//test_5(); // UNCOMMENT before checking test_6()
test_6();
return 0;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]