2013-02-12 20 views
6

Thư viện GObject thực sự là tài liệu khủng khiếp. Thật khó để xác định mục đích của các thực thể được tạo ra. Cụ thể, tôi không nhận được vai trò của GValue, GTypeValueTable, GTypeInfo, GParamSpecTypeData.Mục đích của GValue, GTypeValueTable, GTypeInfo và GParamSpec

Tóm lại, quy trình đăng ký kiểu như sau. Mỗi loại được thể hiện bằng cấu trúc TypeNode. Có 2 kho cấu trúc TypeNode: static_fundamental_type_nodes array để lưu trữ TypeNodes các loại cơ bản tĩnh và static_type_nodes_ht bảng băm cho các loại tĩnh không cơ bản. Mỗi GType chỉ là địa chỉ bộ nhớ của TypeNode tương ứng trong trường hợp các loại không phải cơ bản hoặc chỉ số của TypeNode trong static_fundamental_type_nodes trong trường hợp các loại cơ bản. Điều gì xảy ra với các loại động - Tôi không biết, hãy giải thích cho tôi nếu bạn có thể. Mã tương ứng nằm trong hàm gtype_init, chịu trách nhiệm khởi tạo hệ thống kiểu: http://git.gnome.org/browse/glib/tree/gobject/gtype.c#n4323.

enter image description here

GValue, GParamSpecGObjectGTypes mình, vì vậy họ đã được đăng ký như các loại.

GValue có nghĩa là được sử dụng để đăng ký giá trị kiểu mới thông qua nó, nhưng làm cách nào ?.

GParametersGParamSpec dường như là bắt buộc để đăng ký GObject loại (không chắc chắn). Làm thế nào chính xác nó được thực hiện? Vai trò của mỗi vai trò là gì?

QUAN TRỌNG QUAN TRỌNG: Vai trò của GTypeValueTable, GTypeInfoTypeData là gì? TypeData được tham chiếu bởi TypeNode và chứa GTypeValueTable cũng như các cấu trúc con BoxedData, ClassData, IFaceData, InstanceData (tại sao Instance, không phải chúng tôi đang đăng ký loại?). Hơn nữa, chúng có vẻ giống nhau, vì tất cả chúng chứa tham chiếu đến base_init/finalize, class_init/finalize có một tham chiếu đến GTypeValueTable.

Vì vậy, hãy phát triển papas, nếu bạn đang đọc, vui lòng tự giải thích! Mô tả mục đích của những cấu trúc bạn sử dụng.

Trả lời

14

duy nhất hai trong số các bạn thực sự cần phải quan tâm, trừ khi bạn đang cố gắng để làm việc trên một số mã mức rất thấp là GValue và GParamType

Tôi sẽ bắt đầu với GParamType

GParamType là dành cho được sử dụng để đăng ký tài sản với GObject. Ví dụ, tôi có một lớp con GObject được gọi là Person, và tôi muốn nó có hai thuộc tính: Name và Age. Trong class_init chức năng tôi sẽ đăng ký các như vậy

{ 
    GParamSpec *pspec; 

    . . . 

    pspec = g_param_spec_string ("name", "Name", "The name of the person", "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); 
    g_object_class_install_property (object_class, PROP_NAME, pspec); 

    pspec = g_param_spec_int ("age", "Age", "The age of the person", 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); 
    g_object_class_install_property (object_class, PROP_AGE, spec); 

    . . . 
} 

Bây giờ bạn có thể gọi g_object_get hoặc g_object_set trên những tài sản và hệ thống sẽ biết làm thế nào để xử lý nó

char *name; 
int age; 
g_object_set (G_OBJECT (person), "name", "Steve", "age", 37, NULL); 
g_object_get (G_OBJECT (person), "name", &name, "age", &age, NULL); 

g_print ("%s is %d years old\n", name, age); 

// And because the type system knows when a property is a string, it knows how to give 
// you a copy of the string, so you need to free it once you've finished with it 
g_free (name); 

Các thông số khác nhau được giải thích ở đây: GParamSpec Có các loại GValue cho tất cả các loại tiêu chuẩn: chuỗi, bool, ints vv và một số thư viện khác như GStreamer sẽ đăng ký các tùy chỉnh riêng của chúng.

Ngoài các thuộc tính cài đặt trên GObjectClass bạn rất hiếm khi cần phải xử lý GParamSpec. Hai dịp chính mà chúng xuất hiện là trong các phương thức GObjectClass set/get_property và GObject thông báo tín hiệu. Nó rất hữu ích trong trường hợp cuối cùng để phát hiện tài sản đã nhận được tín hiệu thông báo, bằng cách gọi g_param_spec_get_name, nhưng thực sự nó tốt hơn để sử dụng thông báo cho cụ thể hơn tín hiệu như vậy:

g_signal_connect (person, "notify::name", G_CALLBACK (name_changed_cb), NULL); 
g_signal_connect (person, "notify::age", G_CALLBACK (age_changed_cb), NULL); 

hơn

g_signal_connect (person, "notify", G_CALLBACK (something_changed_cb), NULL); 

Đôi khi bạn có thể muốn tạo cấu trúc của riêng bạn và sử dụng cấu trúc đó cho các thuộc tính. Ví dụ: nếu tôi có

struct _PersonDetails { 
    char *name; 
    int age; 
} 

và thay vì có hai thuộc tính trên đối tượng Person, tôi muốn có một thuộc tính "chi tiết". Hệ thống loại GLib không biết cách xử lý struct _PersonDetails tùy chỉnh của tôi vì vậy tôi sẽ cần phải tạo một kiểu hộp cho nó, để nó biết cách sao chép/giải phóng một cách chính xác cấu trúc khi nó được truyền xung quanh nội bộ Glib. Và đó là nơi GValue có sẵn.

là để gói các giá trị khác nhau để chúng có thể được sao chép và giải phóng chính xác (nếu cần) và để có thể sử dụng các chức năng chung.

Ví dụ, GObjectClass phương pháp set_Property có nguyên mẫu của

void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) 

này có nghĩa là bất kỳ loại có thể được đại diện bởi một GValue có thể được truyền trong và chức năng cụ thể như set_int_property, set_string_property, set_bool_property không cần thiết.

Điều này cũng có nghĩa là các hàm g_object_setg_object_get biết cách xử lý các tham số được truyền bởi vì nó biết rằng "tên" thuộc tính được đăng ký là loại chuỗi và có chức năng cần thiết để sao chép/miễn phí chuỗi đó.

thêm về GValue thể tìm thấy ở đây - Generic values

Để đăng ký tùy chỉnh của chúng tôi với struct _PersonDetails những hệ thống kiểu GLib chúng ta sẽ tạo ra một loại tùy chỉnh đóng hộp mà nói hệ thống như thế nào để sao chép và miễn phí nó. Các chi tiết đang ở đây: Boxed Types

G_DEFINE_BOXED_TYPE (PersonDetails, person_details, 
        person_details_copy, 
        person_details_free) 
. . . 

static gpointer 
person_details_copy (gpointer data) 
{ 
    struct _PersonDetails *details = (struct _PersonDetails *)data; 
    struct _PersonDetails *copy = g_new (struct _PersonDetails, 1); 

    // We need to copy the string 
    copy->name = g_strdup (details->name); 
    copy->age = details->age; 

    return (gpointer) copy; 
} 

static void 
person_details_free (gpointer data) 
{ 
    struct _PersonDetails *details = (struct _PersonDetails *)data; 

    // name was allocated so it needs freed as well 
    g_free (details->name); 

    g_free (details); 
} 

Bây giờ chúng ta có thể đăng ký kiểu của chúng tôi sử dụng

pspec = g_param_spec_boxed ("details", "Details", "The person's details", person_details_get_type(), G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); 
g_object_class_install_property (object_class, PROP_DETAILS, pspec); 
+0

lời giải thích tốt nhất và rõ ràng nhất về chủ đề này tôi đọc đến bây giờ. +1 – drahnr

+0

cuộc gọi g_param_spec_gtype() là sai trong trường hợp này: đối với các loại được đóng hộp, bạn nên sử dụng g_param_spec_boxed(); g_param_spec_gtype() dành cho các thuộc tính lưu trữ giá trị GType thực tế. Ngoài ra, để đăng ký một kiểu đóng hộp, bạn nên sử dụng macro G_DEFINE_BOXED_TYPE(), tạo ra hàm get_type() cho bạn. – ebassi

+0

@ebassi đã sửa cuộc gọi _spec_boxed. – iain