Just as with C++, there are many different ways to define object methods and extend them: the following list and sections draw on C++ vocabulary. (Readers are expected to know basic C++ buzzwords. Those who have not had to write C++ code recently can refer to e.g. http://www.cplusplus.com/doc/tutorial/ to refresh their memories.)
These are the simplest: you want to provide a simple method which can act on your object. All you need to do is to provide a function prototype in the header and an implementation of that prototype in the source file.
/* declaration in the header. */
void maman_bar_do_action (MamanBar *self, /* parameters */);
/* implementation in the source file */
void
maman_bar_do_action (MamanBar *self, /* parameters */)
{
g_return_if_fail (MAMAN_IS_BAR (self));
/* do stuff here. */
}
There is really nothing scary about this. This is the preferred way to create polymorphic GObjects. All you need to do is to define the common method and its class function in the public header, implement the common method in the source file and re-implement the class function in each object which inherits from you.
/* declaration in maman-bar.h. */
struct _MamanBarClass
{
GObjectClass parent_class;
/* stuff */
void (*do_action) (MamanBar *self, /* parameters */);
};
void maman_bar_do_action (MamanBar *self, /* parameters */);
/* implementation in maman-bar.c */
void
maman_bar_do_action (MamanBar *self, /* parameters */)
{
g_return_if_fail (MAMAN_IS_BAR (self));
MAMAN_BAR_GET_CLASS (self)->do_action (self, /* parameters */);
}
The code above simply redirects the do_action call to the relevant
class function. Some users, concerned about performance, do not
provide the
Other users, also concerned by performance issues, declare
the
In doubt, unless a user shows you hard numbers about the performance
cost of the function call, just implement
Please, note that it is possible for you to provide a default
implementation for this class method in the object's
static void
maman_bar_real_do_action_two (MamanBar *self, /* parameters */)
{
/* Default implementation for the virtual method. */
}
static void
maman_bar_class_init (BarClass *klass)
{
/* pure virtual method: mandates implementation in children. */
klass->do_action_one = NULL;
/* merely virtual method. */
klass->do_action_two = maman_bar_real_do_action_two;
}
void
maman_bar_do_action_one (MamanBar *self, /* parameters */)
{
g_return_if_fail (MAMAN_IS_BAR (self));
MAMAN_BAR_GET_CLASS (self)->do_action_one (self, /* parameters */);
}
void
maman_bar_do_action_two (MamanBar *self, /* parameters */)
{
g_return_if_fail (MAMAN_IS_BAR (self));
MAMAN_BAR_GET_CLASS (self)->do_action_two (self, /* parameters */);
}
These are very similar to Virtual Public methods. They just don't have a public function to call the function directly. The header file contains only a declaration of the class function:
/* declaration in maman-bar.h. */
struct _MamanBarClass
{
GObjectClass parent;
/* stuff */
void (* helper_do_specific_action) (MamanBar *self, /* parameters */);
};
void maman_bar_do_any_action (MamanBar *self, /* parameters */);
These class functions are often used to delegate part of the job to child classes:
/* this accessor function is static: it is not exported outside of this file. */
static void
maman_bar_do_specific_action (MamanBar *self, /* parameters */)
{
MAMAN_BAR_GET_CLASS (self)->do_specific_action (self, /* parameters */);
}
void
maman_bar_do_any_action (MamanBar *self, /* parameters */)
{
/* random code here */
/*
* Try to execute the requested action. Maybe the requested action
* cannot be implemented here. So, we delegate its implementation
* to the child class:
*/
maman_bar_do_specific_action (self, /* parameters */);
/* other random code here */
}
Again, it is possible to provide a default implementation for this private virtual class function:
static void
maman_bar_class_init (MamanBarClass *klass)
{
/* pure virtual method: mandates implementation in children. */
klass->do_specific_action_one = NULL;
/* merely virtual method. */
klass->do_specific_action_two = maman_bar_real_do_specific_action_two;
}
Children can then implement the subclass with code such as:
static void
maman_bar_subtype_class_init (MamanBarSubTypeClass *klass)
{
MamanBarClass *bar_class = MAMAN_BAR_CLASS (klass);
/* implement pure virtual class function. */
bar_class->do_specific_action_one = maman_bar_subtype_do_specific_action_one;
}
|