I'm trying to follow the GObject Tutorial to implement my first GObject class. So far, I've come up with this code:
train.h:
#pragma once
#include <glib-object.h>
G_BEGIN_DECLS
#define EXAMPLE_TYPE_TRAIN example_train_get_type ()
G_DECLARE_DERIVABLE_TYPE (ExampleTrain, example_train, EXAMPLE, TRAIN, GObject)
struct _ExampleTrainClass
{
GObjectClass parent_class;
void (* get_route) (ExampleTrain *train);
};
ExampleTrain *example_train_new (void);
G_END_DECLS
train.c:
#include "train.h"
typedef struct {
char *origin;
} ExampleTrainPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (ExampleTrain, example_train, G_TYPE_OBJECT)
static void
example_train_class_init (ExampleTrainClass *klass)
{
}
static void
example_train_init (ExampleTrain *self)
{
ExampleTrainPrivate *priv = example_train_get_instance_private (self);
}
Of course, it doesn't really do anything yet, but it compiles and so I thought I could try to instantiate it. Given that in the header I prototype example_train_new ()
, I presumed that I then could use this in my main.c file to instantiate this class, but no dice:
[1/2] Compiling C object src/gobject-inheritance.p/main.c.o
../../../../../gobject-inheritance/src/main.c: In function ‘main’:
../../../../../gobject-inheritance/src/main.c:13:17: warning: unused variable ‘train_one’ [-Wunused-variable]
13 | ExampleTrain *train_one = example_train_new ();
| ^~~~~~~~~
[2/2] Linking target src/gobject-inheritance
FAILED: src/gobject-inheritance
cc -o src/gobject-inheritance src/gobject-inheritance.p/fruit.c.o src/gobject-inheritance.p/main.c.o src/gobject-inheritance.p/train.c.o -L/app/lib -Wl,--as-needed -Wl,--no-undefined -Wl,--start-group /usr/lib/x86_64-linux-gnu/libglib-2.0.so /usr/lib/x86_64-linux-gnu/libgobject-2.0.so -Wl,--end-group
/usr/lib/gcc/x86_64-unknown-linux-gnu/14.2.0/../../../../x86_64-unknown-linux-gnu/bin/ld: src/gobject-inheritance.p/main.c.o: in function `main':
/mnt/storage/Programming/.gnome-builder/projects/gobject-inheritance/builds/org.gnome.Example.json-flatpak-org.freedesktop.Platform-24.08-x86_64-main/../../../../../gobject-inheritance/src/main.c:13:(.text+0x10): undefined reference to `example_train_new'
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
If I'm reading this error right, the problem seems to be that the linker can't find any definition for example_train_new ()
. While it might seem sensible to just define it myself, in the linked tutorial I don't see this done anywhere.
What am I doing wrong here? Should I implement the "new" method myself?
I ended up looking at some implementations in the GTK 4 source code for how to do this. Specifically, gtk/gtkstack.c.
For the case above, a simple constructor like this seems to suffice:
ExampleTrain *
example_train_new (void)
{
return g_object_new (EXAMPLE_TYPE_TRAIN, NULL);
}
However, if one also for example wants to set the private origin
property from the example above in the constructor, you can do this:
ExampleTrain *
example_train_new (const char *origin)
{
ExampleTrain *self = g_object_new (EXAMPLE_TYPE_TRAIN, NULL);
ExampleTrainPrivate *priv = example_train_get_instance_private (self);
priv->origin = origin;
return self;
}
If you wanted to set a public property, you would do the same as the above but instead use self
in place of priv
. So, the whole example_train_get_instance_private (self)
part could be removed if you don't have any private properties to set.