首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >GObject面向对象语法

GObject面向对象语法
EN

Stack Overflow用户
提问于 2015-01-07 15:54:05
回答 1查看 1.1K关注 0票数 3

我正在寻找一个GObject备忘单,OOP概念如何映射到GObject的工具。例如,考虑:

代码语言:javascript
复制
AnyGObject *o;
o = anygobject_new();

现在,有什么约定.

  • 调用方法
  • 调用基类声明的方法
  • 调用由类实现的接口声明的方法。
  • 调用类方法
  • 调用基类声明的类方法
  • 调用虚拟方法
  • 转换为基类
  • 转换为派生类
  • 转换到类正在实现的接口。
  • 测试对象是否属于特定类型
  • ..。

说明:GObject参考手册GObject HowTo详细解释了如何创建一个新类(类结构、对象结构、私有结构、各种宏、约定)。把这些设施加在一起,就可以实现OOP。然而,似乎没有关于如何始终如一地使用它们的教程。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-01-07 16:59:11

这个答案假设您正在使用C.其他语言(通常是面向对象的)具有特殊的绑定,以使使用GObject看起来更自然。

如果您曾经使用过GTK+,那么您已经完成了该列表的大部分工作。

GObject方法本身并不是成员(有一个vtable类型,但它仅用于在第一次创建类时在派生类中分配虚拟方法实现)。相反,GObject中的所有方法都只是简单的函数,通常(?)以方法名前缀作为前缀,并以this指针作为第一个参数。

例如,C++方法

代码语言:javascript
复制
namespace Lib { // short for Library; to demonstrate GObject's idiomatic naming conventions
    class Foo {
    public:
        void Bar(int z);
    };
}

将是全局命名空间中声明为

代码语言:javascript
复制
void lib_foo_bar(LibFoo *foo, int z);

你可以直接调用它,就像任何其他C函数一样。

GObject中的类派生是通过将父类的完整数据结构作为派生类数据结构的第一个成员来实现的。由于与C标准中很少讨论的子句有关的各种原因(可能还有System和gcc、clang甚至Microsoft C编译器的实现),这意味着指向派生类的对象的指针等同于指向父类的指针!

因此,如果LibBaz是从LibFoo派生出来的,那么您所需要说的就是

代码语言:javascript
复制
LibFoo *foobaz = (LibFoo *) baz;

相反的情况也是如此:

代码语言:javascript
复制
LibBaz *bazfoo = (LibBaz *) foo;

(后一种方法是GTK+用于GtkWidget的方法;我不知道其他GObject库是否做了同样的事情。)

惯用的GObject声明包括一系列宏,这些宏使类型转换更加简洁,同时添加运行时类型安全检查。我们的LibFoo类将具有以下宏:

代码语言:javascript
复制
#define LIB_TYPE_FOO (lib_foo_get_type())
#define LIB_FOO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), LIB_TYPE_FOO, LibFoo))

有了这个,我们会说

代码语言:javascript
复制
LibFoo *foobaz = LIB_FOO(baz);
LibBaz *bazfoo = LIB_BAZ(foo);

如果bazfoo不是转换的正确类型,则会将警告记录到标准错误,您可以使用调试器中断该错误并进行调查。

( lib_foo_get_type()函数(和LIB_TYPE_FOO整洁宏)很重要:它返回一个数字ID,该ID映射到LibFoo类型以供将来参考。如果LibFoo没有这样的映射,它将创建映射、注册类型和创建虚拟方法映射。)

类似的宏允许类型检查:

代码语言:javascript
复制
#define LIB_IS_FOO(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), LIB_TYPE_FOO))

这是一个可以在if语句中使用的简单表达式。

那么调用父类方法呢?好吧,如果我们把所有这些都放在一起,我们就有了答案:

代码语言:javascript
复制
lib_foo_parent_method(LIB_FOO(aLibBazInstance), params);

这同样适用于虚拟方法。虚拟方法是使用vtables的GObject近似实现的,对最终程序员来说是透明的。你要做的就是

代码语言:javascript
复制
lib_foo_virtual_method(LIB_FOO(whatever), params);

(如果您实际构建了派生类本身,那么虚拟方法的方式就变得非常重要。)

在GObject中没有静态方法,因为方法与类的联系并不像在真实的面向对象语言中那样紧密。只需在库中创建一个顶级方法:

代码语言:javascript
复制
void lib_something_common(params);

最后,所有这些都适用于接口。接口对最终用户的工作方式完全相同;它们使用的是相同的

代码语言:javascript
复制
void lib_iface_method(LibIface *iface, params);

方法调用方法、相同的转换规则以及相同的LIB_IFACE()LIB_IS_IFACE()助手宏。

希望这能帮上忙!任何进一步的解释都必须深入解释如何创建GObject,为了简单起见,我试图将其保留在这个答案的范围之外,但无论如何,了解它是一件有用的事情。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27823299

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档