【问题标题】:GObject subclassing in C unable to create a subclass instanceC中的GObject子类化无法创建子类实例
【发布时间】:2016-08-02 17:04:27
【问题描述】:

我想试试 GObject API。这个想法是创建一个DERIVABLE 类型的Vehicule 类,并创建一个名为Car 的Vehicule 子类,它是一个FINAL 类型。我的问题是,当我尝试在一个小程序中创建一个 Car 类时,我的程序会阻塞并且不会在实例创建时返回。

这是重现我的问题的最少代码。我使用约定 tuto-vehicule /tuto-car。

tuto-vehicule.h

#ifndef __TUTO_VEHICULE_H__
#define __TUTO_VEHICULE_H__
#include <glib-object.h>

G_BEGIN_DECLS

typedef struct _TutoVehiculePrivate {
    GObject parent_instance;
    GString *name;
    guint nb_wheels;
} TutoVehiculePrivate;

typedef struct _TutoVehiculeClass {
    GObjectClass parent_class;
} TutoVehiculeClass;

#define TUTO_TYPE_VEHICULE tuto_vehicule_get_type()
G_DECLARE_DERIVABLE_TYPE(TutoVehicule, tuto_vehicule, TUTO, VEHICULE, GObject);


TutoVehicule *tuto_vehicule_new (void);

void tuto_vehicule_set_name(TutoVehicule *self, gchar *name);
void tuto_vehicule_set_nb_wheels(TutoVehicule *self, gint nb_wheels);
void tuto_vehicule_print_name(TutoVehicule *self);
void tuto_vehicule_print_nb_wheels(TutoVehicule *self);

G_END_DECLS

#endif

tuto-vehicule.c

#include "tuto-vehicule.h"
#include <stdio.h>

G_DEFINE_TYPE_WITH_PRIVATE(TutoVehicule, tuto_vehicule, G_TYPE_OBJECT);

static void
tuto_vehicule_dispose(GObject *object)
{
    TutoVehiculePrivate *priv = tuto_vehicule_get_instance_private(TUTO_VEHICULE(object));
    printf("tuto_vehicule_dispose\n");
    g_string_free(priv->name, TRUE);
    G_OBJECT_CLASS(tuto_vehicule_parent_class)->dispose(object);
}

static void
tuto_vehicule_class_init(TutoVehiculeClass *klass)
{
    GObjectClass *g_object_class = G_OBJECT_CLASS(klass);
    /* instance destructor*/
    g_object_class->dispose = tuto_vehicule_dispose;
    printf("tuto_vehicule_class_init for TutoVehiculeClass created by G_DECLARE_DERIVABLE_TYPE\n");
}

static void
tuto_vehicule_init(TutoVehicule *self)
{
    TutoVehiculePrivate *priv = tuto_vehicule_get_instance_private(self);
    priv->name = g_string_new(NULL);
    priv->nb_wheels = 0;
    printf("tuto_vehicule_init\n");
}

TutoVehicule *
tuto_vehicule_new(void)
{
    TutoVehicule *vehicule_instance = g_object_new(TUTO_TYPE_VEHICULE, NULL);
    return vehicule_instance;
}

void tuto_vehicule_set_name(TutoVehicule *self, gchar *name)
{
    TutoVehiculePrivate *priv = tuto_vehicule_get_instance_private(self);
    g_string_assign(priv->name, name);
}

void tuto_vehicule_set_nb_wheels(TutoVehicule *self, gint nb_wheels)
{
    TutoVehiculePrivate *priv = tuto_vehicule_get_instance_private(self);
    priv->nb_wheels = nb_wheels;
}

void tuto_vehicule_print_name(TutoVehicule *self)
{
    TutoVehiculePrivate *priv = tuto_vehicule_get_instance_private(self);
    printf("Vehicule name: %s\n", priv->name->str);
}

void tuto_vehicule_print_nb_wheels(TutoVehicule *self)
{
    TutoVehiculePrivate *priv = tuto_vehicule_get_instance_private(self);
    printf("Vehicule number of wheels: %d\n", priv->nb_wheels);
}

tuto-car.h

#ifndef __TUTO_CAR_H
#define __TUTO_CAR_H
#include "tuto-vehicule.h"
#include <glib-object.h>

G_BEGIN_DECLS

#define TUTO_TYPE_CAR tuto_car_get_type ()
G_DECLARE_FINAL_TYPE(TutoCar, tuto_car, TUTO, CAR, TutoVehicule);

typedef struct _TutoCar {
    TutoVehicule parent_instance;
} TutoCar;

TutoCar *tuto_car_new(void);
void tuto_car_print_name(TutoCar *self);
void tuto_car_print_nb_wheels(TutoCar *self);
G_END_DECLS
#endif

tuto-car.c

#include "tuto-car.h"
#include <stdio.h>

G_DEFINE_TYPE(TutoCar, tuto_car, TUTO_TYPE_CAR);

static void
tuto_car_class_init(TutoCarClass *klass)
{
    printf("tuto_car_class_init\n");
}

static void
tuto_car_init(TutoCar *self)
{
    printf("tuto_car_init\n");
}

TutoCar *
tuto_car_new(void)
{
    TutoCar *car = g_object_new(TUTO_TYPE_CAR, NULL);
    tuto_vehicule_set_name(TUTO_VEHICULE(car), "car");
    tuto_vehicule_set_nb_wheels(TUTO_VEHICULE(car), 4);
    return car;
}

void
tuto_car_print_name(TutoCar *self)
{
    tuto_vehicule_print_name(TUTO_VEHICULE(self));
}

void
tuto_car_print_nb_wheels(TutoCar *self)
{
    tuto_vehicule_print_nb_wheels(TUTO_VEHICULE(self));
}

我在一个简单的主文件中使用这两个类:

#include <stdio.h>
#include "tuto-vehicule.h"
#include "tuto-car.h"

int main(int argc, char **argv)
{
    printf("Create a TutoVehicule instance\n");

    TutoVehicule *moto = tuto_vehicule_new();
    printf("Puts its name to moto\n");
    tuto_vehicule_set_name(moto, "moto");
    printf("Puts its number of wheels to 2\n");
    tuto_vehicule_set_nb_wheels(moto, 2);

    printf("Create a TutoCar instance\n");
    TutoCar *car = tuto_car_new();

    printf("Use methods instance\n");

    tuto_vehicule_print_name(moto);
    tuto_vehicule_print_nb_wheels(moto);

    tuto_vehicule_print_name(TUTO_VEHICULE(car));
    tuto_vehicule_print_nb_wheels(TUTO_VEHICULE(car));

    tuto_car_print_name(car);
    tuto_car_print_nb_wheels(car);

    printf("Destroy the instances created previously\n");
    g_object_unref(car);
    g_object_unref(moto);

    return 0;
}

编译适用于:

gcc -Wall -o main_vehicule `pkg-config --libs --cflags gobject-2.0` main_vehicule.c tuto-car.c tuto-vehicule.c

但是当我运行程序时,如下所述,我有这个输出和程序块,没有返回也没有发出错误消息:

Create a TutoVehicule instance
tuto_vehicule_class_init for TutoVehiculeClass created by G_DECLARE_DERIVABLE_TYPE
tuto_vehicule_init
Puts its name to moto
Puts its number of wheels to 2
Create a TutoCar instance

我知道我的程序在这个语句处阻塞:

TutoCar *car = g_object_new(TUTO_TYPE_CAR, NULL);

我错过了什么?官方文档不是很清楚。

编辑

这是一个 gdb 会话:

(gdb) break tuto-car.c:tuto_car_new
Breakpoint 1 at 0x400dcb: file tuto-car.c, line 21.
(gdb) run
Starting program: /home/cedlemo/Projets/C/GObject/derivable_type/main_vehicule 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".
Create a TutoVehicule instance
tuto_vehicule_class_init for TutoVehiculeClass created by G_DECLARE_DERIVABLE_TYPE
tuto_vehicule_init
Puts its name to moto
Puts its number of wheels to 2
Create a TutoCar instance

Breakpoint 1, tuto_car_new () at tuto-car.c:21
21      TutoCar *car = g_object_new(TUTO_TYPE_CAR, NULL);
(gdb) backtrace
#0  tuto_car_new () at tuto-car.c:21
#1  0x0000000000400c02 in main (argc=1, argv=0x7fffffffded8) at main_vehicule.c:16
(gdb) next

gdb 中的程序块也是如此,所以我不得不点击 ctrl+c 并检查堆栈:

(gdb) backtrace
#0  0x00007ffff75ba269 in syscall () from /usr/lib/libc.so.6
#1  0x00007ffff790618f in g_cond_wait () from /usr/lib/libglib-2.0.so.0
#2  0x00007ffff78e8437 in g_once_init_enter () from /usr/lib/libglib-2.0.so.0
#3  0x0000000000400d1e in tuto_car_get_type () at tuto-car.c:4
#4  0x0000000000400d44 in tuto_car_get_type () at tuto-car.c:4
#5  0x0000000000400dd0 in tuto_car_new () at tuto-car.c:21
#6  0x0000000000400c02 in main (argc=1, argv=0x7fffffffded8) at main_vehicule.c:16

【问题讨论】:

  • 请注意以下内容:“请注意,以双下划线或下划线和大写字母开头的符号无条件保留用于实现。是的,系统标头使用带有双下划线的名称 - 它们”作为实现的一部分,并且不允许污染您的命名空间。您不应该污染他们的命名空间。出于所有实际目的,尽管有多个反例,请将以下划线开头的名称视为为编译器保留的名称。“
  • @user3629249,例如,如果您指的是 _TutoCar 或 _TutoVehiculePrivate,我只是遵循 GObject 约定,请参阅:developer.gnome.org/gobject/2.48/howto-gobject.htmldeveloper.gnome.org/gobject/2.48/howto-gobject-code.html
  • 我意识到,这确实是一个极小的示例,因为 GObject 代码非常冗长;您可以通过删除车轮属性的名称和数量来使其更小,看看这是否会影响任何事情。在任何情况下,我都会使用调试器来查看程序真正冻结的位置,而不是依赖打印语句。目前,我将投票重新开放,因为我认为问题陈述很清楚。
  • 我已经添加了一些gdb信息。

标签: c glib gobject


【解决方案1】:

这是答案:

在文件 tuto-car.c 中,我是一行:

G_DEFINE_TYPE(TutoCar, tuto_car, TUTO_TYPE_CAR);

对于这两个宏:

  • G_DEFINE_TYPE
  • G_DEFINE_TYPE_WITH_PRIVATE

最后一个参数是父级的 GType。在我的代码中,我使用了它自己的类的 GType。我应该使用TUTO_TYPE_VEHICULE

G_DEFINE_TYPE(TutoCar, tuto_car, TUTO_TYPE_VEHICULE);

有了这个,之前的代码就可以正常工作了。

【讨论】:

    猜你喜欢
    • 2019-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-28
    • 2011-10-11
    • 1970-01-01
    • 2017-04-10
    • 1970-01-01
    相关资源
    最近更新 更多