Message ID | 1358407910-6031-1-git-send-email-afaerber@suse.de |
---|---|
State | New |
Headers | show |
On Thu, Jan 17, 2013 at 08:31:50AM +0100, Andreas Färber wrote: > Add a documentation section "Methods" and discuss among others how to > handle overriding virtual methods. > > Clarify DeviceClass::realize documentation and refer to the above. > > Signed-off-by: Andreas Färber <afaerber@suse.de> > --- > hw/qdev-core.h | 14 +++++-- > include/qom/object.h | 104 ++++++++++++++++++++++++++++++++++++++++++++++++-- > 2 Dateien geändert, 111 Zeilen hinzugefügt(+), 7 Zeilen entfernt(-) > > diff --git a/hw/qdev-core.h b/hw/qdev-core.h > index 3d75ae2..731aadd 100644 > --- a/hw/qdev-core.h > +++ b/hw/qdev-core.h > @@ -60,14 +60,20 @@ struct VMStateDescription; > * The @init callback is considered private to a particular bus implementation > * (immediate abstract child types of TYPE_DEVICE). Derived leaf types set an > * "init" callback on their parent class instead. > + * > * Any type may override the @realize and/or @unrealize callbacks but needs > - * to call (and thus save) the parent type's implementation if so desired. > - * Usually this means storing the previous value of, e.g., @realized inside > - * the type's class structure and overwriting it with a function that first > - * invokes the stored callback, then performs any additional steps. > + * to call the parent type's implementation if keeping their functionality > + * is desired. Refer to QOM documentation for further discussion and examples. > + * > + * <note> > + * <para> > * If a type derived directly from TYPE_DEVICE implements @realize, it does > * not need to implement @init and therefore does not need to store and call > * #DeviceClass' default @realize callback. > + * For other types consult the documentation and implementation of the > + * respective parent types. > + * </para> > + * </note> The above looks clearer to me, thanks! But I still have a question about the preferred method to make subclasses call the parent implementation, below: > */ > typedef struct DeviceClass { > /*< private >*/ > diff --git a/include/qom/object.h b/include/qom/object.h > index 1ef2f0e..8e16ea8 100644 > --- a/include/qom/object.h > +++ b/include/qom/object.h > @@ -147,9 +147,9 @@ typedef struct InterfaceInfo InterfaceInfo; > * </programlisting> > * </example> > * > - * Introducing new virtual functions requires a class to define its own > - * struct and to add a .class_size member to the TypeInfo. Each function > - * will also have a wrapper to call it easily: > + * Introducing new virtual methods requires a class to define its own > + * struct and to add a .class_size member to the #TypeInfo. Each method > + * will also have a wrapper function to call it easily: > * > * <example> > * <title>Defining an abstract class</title> > @@ -186,6 +186,104 @@ typedef struct InterfaceInfo InterfaceInfo; > * similar to normal types except for the fact that are only defined by > * their classes and never carry any state. You can dynamically cast an object > * to one of its #Interface types and vice versa. > + * > + * # Methods # > + * > + * A <emphasis>method</emphasis> is a function within the namespace scope of > + * a class. It usually operates on the object instance by passing it as a > + * strongly-typed first argument. > + * If it does not operate on an object instance, it is dubbed > + * <emphasis>class method</emphasis>. > + * > + * Methods cannot be overloaded. That is, the #ObjectClass and method name > + * uniquely identity the function to be called; the signature does not vary > + * except for trailing varargs. > + * > + * Methods are always <emphasis>virtual</emphasis>. Overriding a method in > + * #TypeInfo.class_init of a subclass leads to any user of the class obtained > + * via OBJECT_GET_CLASS() accessing the overridden function. > + * The original function is not automatically invoked. It is the responsability > + * of the overriding class to determine whether and when to invoke the method > + * being overridden. > + * > + * To invoke the method being overridden, the preferred solution is to store > + * the original value in the overriding class before overriding the method. > + * This corresponds to |[ {super,base}.method(...) ]| in Java and C# > + * respectively; this frees the overriding class from hardcoding its parent > + * class, which someone might choose to change at some point. > + * > + * <example> > + * <title>Overriding a virtual method</title> > + * <programlisting> > + * typedef struct MyState MyState; > + * > + * typedef void (*MyDoSomething)(MyState *obj); > + * > + * typedef struct MyClass { > + * ObjectClass parent_class; > + * > + * MyDoSomething do_something; > + * } MyClass; > + * > + * static void my_do_something(MyState *obj) > + * { > + * // do something > + * } > + * > + * static void my_class_init(ObjectClass *oc, void *data) > + * { > + * MyClass *mc = MY_CLASS(oc); > + * > + * mc->do_something = my_do_something; > + * } > + * > + * static const TypeInfo my_type_info = { > + * .name = TYPE_MY, > + * .parent = TYPE_OBJECT, > + * .instance_size = sizeof(MyState), > + * .class_size = sizeof(MyClass), > + * .class_init = my_class_init, > + * }; > + * > + * typedef struct DerivedClass { > + * MyClass parent_class; > + * > + * MyDoSomething parent_do_something; > + * } MyClass; > + * > + * static void derived_do_something(MyState *obj) > + * { > + * DerivedClass *dc = DERIVED_GET_CLASS(obj); > + * > + * // do something here > + * dc->parent_do_something(obj); > + * // do something else here > + * } > + * > + * static void derived_class_init(ObjectClass *oc, void *data) > + * { > + * MyClass *mc = MY_CLASS(oc); > + * DerivedClass *dc = DERIVED_CLASS(oc); > + * > + * dc->parent_do_something = mc->do_something; > + * mc->do_something = derived_do_something; > + * } > + * > + * static const TypeInfo derived_type_info = { > + * .name = TYPE_DERIVED, > + * .parent = TYPE_MY, > + * .class_size = sizeof(DerivedClass), > + * .class_init = my_class_init, > + * }; > + * </programlisting> > + * </example> > + * > + * Alternatively, object_class_by_name() can be used to obtain the class and > + * its non-overridden methods for a specific type. This would correspond to > + * |[ MyClass::method(...) ]| in C++. I still wonder why resolving/saving/calling thie parent class method at runtime (using any of the two methods described above) is better than simply making the corresponding parent_class_method() function public, so it can be called directly by classes that override the method. Is there any use-case where resolving the parent class implementation at runtime is really necessary? > + * > + * The first example of such a QOM method was #CPUClass.reset, > + * another example is #DeviceClass.realize. > */ > > > -- > 1.7.10.4 >
Eduardo Habkost <ehabkost@redhat.com> writes: > On Thu, Jan 17, 2013 at 08:31:50AM +0100, Andreas Färber wrote: >> + * Alternatively, object_class_by_name() can be used to obtain the class and >> + * its non-overridden methods for a specific type. This would correspond to >> + * |[ MyClass::method(...) ]| in C++. > > I still wonder why resolving/saving/calling thie parent class method at > runtime (using any of the two methods described above) is better than > simply making the corresponding parent_class_method() function public, > so it can be called directly by classes that override the method. It's idiomatic from GObject. I'm not sure I can come up with a concrete example but in the absense of a compelling reason to shift from the idiom, I'd strongly suggest not. Regards, Anthony Liguori > > Is there any use-case where resolving the parent class implementation at > runtime is really necessary? > > >> + * >> + * The first example of such a QOM method was #CPUClass.reset, >> + * another example is #DeviceClass.realize. >> */ >> >> >> -- >> 1.7.10.4 >> > > -- > Eduardo
Applied. Thanks. Regards, Anthony Liguori
diff --git a/hw/qdev-core.h b/hw/qdev-core.h index 3d75ae2..731aadd 100644 --- a/hw/qdev-core.h +++ b/hw/qdev-core.h @@ -60,14 +60,20 @@ struct VMStateDescription; * The @init callback is considered private to a particular bus implementation * (immediate abstract child types of TYPE_DEVICE). Derived leaf types set an * "init" callback on their parent class instead. + * * Any type may override the @realize and/or @unrealize callbacks but needs - * to call (and thus save) the parent type's implementation if so desired. - * Usually this means storing the previous value of, e.g., @realized inside - * the type's class structure and overwriting it with a function that first - * invokes the stored callback, then performs any additional steps. + * to call the parent type's implementation if keeping their functionality + * is desired. Refer to QOM documentation for further discussion and examples. + * + * <note> + * <para> * If a type derived directly from TYPE_DEVICE implements @realize, it does * not need to implement @init and therefore does not need to store and call * #DeviceClass' default @realize callback. + * For other types consult the documentation and implementation of the + * respective parent types. + * </para> + * </note> */ typedef struct DeviceClass { /*< private >*/ diff --git a/include/qom/object.h b/include/qom/object.h index 1ef2f0e..8e16ea8 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -147,9 +147,9 @@ typedef struct InterfaceInfo InterfaceInfo; * </programlisting> * </example> * - * Introducing new virtual functions requires a class to define its own - * struct and to add a .class_size member to the TypeInfo. Each function - * will also have a wrapper to call it easily: + * Introducing new virtual methods requires a class to define its own + * struct and to add a .class_size member to the #TypeInfo. Each method + * will also have a wrapper function to call it easily: * * <example> * <title>Defining an abstract class</title> @@ -186,6 +186,104 @@ typedef struct InterfaceInfo InterfaceInfo; * similar to normal types except for the fact that are only defined by * their classes and never carry any state. You can dynamically cast an object * to one of its #Interface types and vice versa. + * + * # Methods # + * + * A <emphasis>method</emphasis> is a function within the namespace scope of + * a class. It usually operates on the object instance by passing it as a + * strongly-typed first argument. + * If it does not operate on an object instance, it is dubbed + * <emphasis>class method</emphasis>. + * + * Methods cannot be overloaded. That is, the #ObjectClass and method name + * uniquely identity the function to be called; the signature does not vary + * except for trailing varargs. + * + * Methods are always <emphasis>virtual</emphasis>. Overriding a method in + * #TypeInfo.class_init of a subclass leads to any user of the class obtained + * via OBJECT_GET_CLASS() accessing the overridden function. + * The original function is not automatically invoked. It is the responsability + * of the overriding class to determine whether and when to invoke the method + * being overridden. + * + * To invoke the method being overridden, the preferred solution is to store + * the original value in the overriding class before overriding the method. + * This corresponds to |[ {super,base}.method(...) ]| in Java and C# + * respectively; this frees the overriding class from hardcoding its parent + * class, which someone might choose to change at some point. + * + * <example> + * <title>Overriding a virtual method</title> + * <programlisting> + * typedef struct MyState MyState; + * + * typedef void (*MyDoSomething)(MyState *obj); + * + * typedef struct MyClass { + * ObjectClass parent_class; + * + * MyDoSomething do_something; + * } MyClass; + * + * static void my_do_something(MyState *obj) + * { + * // do something + * } + * + * static void my_class_init(ObjectClass *oc, void *data) + * { + * MyClass *mc = MY_CLASS(oc); + * + * mc->do_something = my_do_something; + * } + * + * static const TypeInfo my_type_info = { + * .name = TYPE_MY, + * .parent = TYPE_OBJECT, + * .instance_size = sizeof(MyState), + * .class_size = sizeof(MyClass), + * .class_init = my_class_init, + * }; + * + * typedef struct DerivedClass { + * MyClass parent_class; + * + * MyDoSomething parent_do_something; + * } MyClass; + * + * static void derived_do_something(MyState *obj) + * { + * DerivedClass *dc = DERIVED_GET_CLASS(obj); + * + * // do something here + * dc->parent_do_something(obj); + * // do something else here + * } + * + * static void derived_class_init(ObjectClass *oc, void *data) + * { + * MyClass *mc = MY_CLASS(oc); + * DerivedClass *dc = DERIVED_CLASS(oc); + * + * dc->parent_do_something = mc->do_something; + * mc->do_something = derived_do_something; + * } + * + * static const TypeInfo derived_type_info = { + * .name = TYPE_DERIVED, + * .parent = TYPE_MY, + * .class_size = sizeof(DerivedClass), + * .class_init = my_class_init, + * }; + * </programlisting> + * </example> + * + * Alternatively, object_class_by_name() can be used to obtain the class and + * its non-overridden methods for a specific type. This would correspond to + * |[ MyClass::method(...) ]| in C++. + * + * The first example of such a QOM method was #CPUClass.reset, + * another example is #DeviceClass.realize. */
Add a documentation section "Methods" and discuss among others how to handle overriding virtual methods. Clarify DeviceClass::realize documentation and refer to the above. Signed-off-by: Andreas Färber <afaerber@suse.de> --- hw/qdev-core.h | 14 +++++-- include/qom/object.h | 104 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 Dateien geändert, 111 Zeilen hinzugefügt(+), 7 Zeilen entfernt(-)