构造 GTK 组合框时从不兼容的指针类型初始化
Initialization from incompatible pointer type when constructing a GTK combobox
GtkComboBoxText *main_combo=gtk_combo_box_text_new();
以上代码产生以下错误:
source.c:31:32: warning: initialization from incompatible pointer type [enabled by default]
GtkComboBoxText *main_combo=gtk_combo_box_text_new();
我不确定我是否理解错误的含义或如何修复它。
简答:
像这样声明组合框:
GtkWidget *main_combo=gtk_combo_box_text_new();
并像这样使用它:
gtk_combo_box_text_insert(GTK_COMBO_BOX_TEXT(main_combo), 0, NULL, "foobar");
长答案:
GTK 小部件遵循面向对象的方法,其中特定小部件类型从更通用的小部件类型继承属性和方法。
例如,根据文档,GtkComboBoxText
具有以下层次结构:
GObject
\-- GInitiallyUnowned
\-- GtkWidget
\-- GtkContainer
\-- GtkBin
\-- GtkComboBox
\-- GtkComboBoxText
另外,widget类型也可以实现接口。例如,从文档中,
GtkComboBoxText implements AtkImplementorIface, GtkBuildable, GtkCellLayout and GtkCellEditable.
这意味着,给定一个指向 GtkComboBoxText
类型对象的指针 ptr
,我可以:
在 GtkComboBoxText 的方法上使用它,例如
gtk_combo_box_text_insert(ptr, 0, NULL, "foobar");
在它继承自的任何类型的方法上使用它,例如
gtk_widget_destroy(ptr);
或
GtkWidget *wid = gtk_bin_get_child(ptr);
在它实现的任何接口的方法上使用它,例如
gtk_cell_editable_start_editing(ptr, event);
因为 C 不是面向对象的语言,当您编译程序时,编译器不知道 GtkComboBoxText
继承自 GtkWidget
。这意味着如果您有一个声明为 GtkComboBoxText
类型的对象,当您在 GtkWidget
的方法中使用它时,编译器会看到一个不兼容的指针,反之亦然。
现在 GTK 的作者有两个明智的对象构造函数选择。例如,对于 gtk_combo_box_text()
,他们可能会选择 return GtkComboBoxText *
,或者他们可能会选择层次结构顶部的有用类型 (GtkWidget *
) 来 return。他们选择了后者。
所以您实际上有几个选项可以修复警告消息:
当您需要将它用于继承类型的方法时转换您的小部件:
GtkWidget *w = gtk_combo_box_text_new();
gtk_combo_box_text_insert(GTK_COMBO_BOX_TEXT(w), 0, NULL, "foobar");
gtk_combo_box_set_active(GTK_COMBO_BOX(w), -1);
gtk_buildable_set_name(GTK_BUILDABLE(w), "name");
gtk_widget_destroy(w); // no cast needed here
初始化时投射您的小部件:
GtkComboBoxText *w = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new());
gtk_combo_box_text_insert(w, 0, NULL, "foobar"); // no cast needed here
gtk_combo_box_set_active(GTK_COMBO_BOX(w), -1);
gtk_buildable_set_name(GTK_BUILDABLE(w), "name");
gtk_widget_destroy(GTK_WIDGET(w));
使用void *
:
void *w = gtk_combo_box_text_new();
gtk_combo_box_text_insert(w, 0, NULL, "foobar");
gtk_combo_box_set_active(w, -1);
gtk_buildable_set_name(w, "name");
gtk_widget_destroy(w);
虽然第三种方法看起来更整洁,但我个人不会推荐它,因为它可能无法检测到一些可能会犯的错误。如果您非常频繁地调用 gtk_combo_box_text_*()
函数并且很少使用其他函数,则第二种方法可能有其优势。然而,我通常使用第一种方法,因为它的用法更加清晰和直接(即在使用 gtk_widget_*()
函数时不要转换,否则转换)。第一种方法也是文档和gtk3-demo中示例中使用的方法。
旁注:
也可以使用传统的 C 风格转换,例如
gtk_combo_box_text_insert((GtkComboBoxText *)main_combo, 0, NULL, "foobar");
但是,宏 GTK_COMBO_BOX_TEXT()
提供了一些错误检查功能,因此如果您不小心传递了不是 GtkComboBoxText 的内容,宏将导致显示错误消息,而 C 风格的转换可能不会。
GtkComboBoxText *main_combo=gtk_combo_box_text_new();
以上代码产生以下错误:
source.c:31:32: warning: initialization from incompatible pointer type [enabled by default] GtkComboBoxText *main_combo=gtk_combo_box_text_new();
我不确定我是否理解错误的含义或如何修复它。
简答:
像这样声明组合框:
GtkWidget *main_combo=gtk_combo_box_text_new();
并像这样使用它:
gtk_combo_box_text_insert(GTK_COMBO_BOX_TEXT(main_combo), 0, NULL, "foobar");
长答案:
GTK 小部件遵循面向对象的方法,其中特定小部件类型从更通用的小部件类型继承属性和方法。
例如,根据文档,GtkComboBoxText
具有以下层次结构:
GObject
\-- GInitiallyUnowned
\-- GtkWidget
\-- GtkContainer
\-- GtkBin
\-- GtkComboBox
\-- GtkComboBoxText
另外,widget类型也可以实现接口。例如,从文档中,
GtkComboBoxText implements AtkImplementorIface, GtkBuildable, GtkCellLayout and GtkCellEditable.
这意味着,给定一个指向 GtkComboBoxText
类型对象的指针 ptr
,我可以:
在 GtkComboBoxText 的方法上使用它,例如
gtk_combo_box_text_insert(ptr, 0, NULL, "foobar");
在它继承自的任何类型的方法上使用它,例如
gtk_widget_destroy(ptr);
或
GtkWidget *wid = gtk_bin_get_child(ptr);
在它实现的任何接口的方法上使用它,例如
gtk_cell_editable_start_editing(ptr, event);
因为 C 不是面向对象的语言,当您编译程序时,编译器不知道 GtkComboBoxText
继承自 GtkWidget
。这意味着如果您有一个声明为 GtkComboBoxText
类型的对象,当您在 GtkWidget
的方法中使用它时,编译器会看到一个不兼容的指针,反之亦然。
现在 GTK 的作者有两个明智的对象构造函数选择。例如,对于 gtk_combo_box_text()
,他们可能会选择 return GtkComboBoxText *
,或者他们可能会选择层次结构顶部的有用类型 (GtkWidget *
) 来 return。他们选择了后者。
所以您实际上有几个选项可以修复警告消息:
当您需要将它用于继承类型的方法时转换您的小部件:
GtkWidget *w = gtk_combo_box_text_new(); gtk_combo_box_text_insert(GTK_COMBO_BOX_TEXT(w), 0, NULL, "foobar"); gtk_combo_box_set_active(GTK_COMBO_BOX(w), -1); gtk_buildable_set_name(GTK_BUILDABLE(w), "name"); gtk_widget_destroy(w); // no cast needed here
初始化时投射您的小部件:
GtkComboBoxText *w = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new()); gtk_combo_box_text_insert(w, 0, NULL, "foobar"); // no cast needed here gtk_combo_box_set_active(GTK_COMBO_BOX(w), -1); gtk_buildable_set_name(GTK_BUILDABLE(w), "name"); gtk_widget_destroy(GTK_WIDGET(w));
使用
void *
:void *w = gtk_combo_box_text_new(); gtk_combo_box_text_insert(w, 0, NULL, "foobar"); gtk_combo_box_set_active(w, -1); gtk_buildable_set_name(w, "name"); gtk_widget_destroy(w);
虽然第三种方法看起来更整洁,但我个人不会推荐它,因为它可能无法检测到一些可能会犯的错误。如果您非常频繁地调用 gtk_combo_box_text_*()
函数并且很少使用其他函数,则第二种方法可能有其优势。然而,我通常使用第一种方法,因为它的用法更加清晰和直接(即在使用 gtk_widget_*()
函数时不要转换,否则转换)。第一种方法也是文档和gtk3-demo中示例中使用的方法。
旁注:
也可以使用传统的 C 风格转换,例如
gtk_combo_box_text_insert((GtkComboBoxText *)main_combo, 0, NULL, "foobar");
但是,宏 GTK_COMBO_BOX_TEXT()
提供了一些错误检查功能,因此如果您不小心传递了不是 GtkComboBoxText 的内容,宏将导致显示错误消息,而 C 风格的转换可能不会。