[software development] GObject简介和入门指引(二)面向对象的概念
Tofloor
poster avatar
enforcee
deepin
2023-08-10 09:41
Author

无论是多么复杂的程序,抽丝剥茧地看,也不过是数据和动作的综合。而正是他们的堆叠组合,才构成了缤纷多彩的计算机系统。C语言中的「变量」和「函数」,就是这两种元素的体现。但是,当程序的体量不断扩大,逻辑逐渐变得复杂,我们便难以通过如此「微观」的方法去观察程序。就如同我们所生活的世界,尽管我们知道世界是由原子和分子组成的,但是我们不会去,也没办法把观察或操作每个单独的分子作为我们的生活方式。而我们了解和接触世界的方式,更多是通过「物体」来进行的。我们编程中使用的「对象」,也是由各种变量和函数组合而成的。而我们会把这样的「对象」作为一个整体去看待,就像我们现实生活中的物体一样。我们与其互动的时,只需要关注他给你展示的功能;而他的内部是如何运行的,我们无需操心。

所谓「面向对象」的理念,就是把操作各种对象作为编程的主要手段。面向对象的编程简化了我们学习的难度,更适合大型项目的协作,尤其适合开发图形界面程序。(当然,GObject就是这样从GTK中诞生的。)实现面向对象的方法有很多,各种面向对象系统的设计和功能也有区别(比如说基于类的面向对象和基于原型的面向对象),而这里我们只介绍一些最基本的内容。

类(Class):在「基于类的面向对象」中,一个类是「同类对象」的统称。我们在这种编程中,实际上是定义了一个「类」,去设定类的特征,这样,我们可以轻松产出一系列具有相同特性的对象。

对象(Object):对象是从一个类中诞生的一个个体,是我们可以互动的东西。因此如果一个个体属于一个类,我们叫这个对象是这个类的「实例(Instance)」,而一个对象从类中诞生的过程我们叫「实例化(instantiate)」。

型(Type):(也被翻译成类型,但是这样的话就很容易混淆。)型是各种数据结构的特征,表示他们相互区分的特质。而不只是对象,任何数据都有型,包括数值、指针等。数据的型可以转换成另一种,而不同的编程语言对这个过程的处理方法也不尽相同。(这里应该有*的笑话。)

方法(Method):其实就是我们C语言中的函数(Function)或者叫过程(Procedure)。其实都没什么区别,只是到了面向对象这里,我们就叫他方法。爱咋咋的。

字段(Field):其实就是变量(Variable)。同上,但是这个名词不怎么普及,可能是和一个图形界面的模块重名了。

成员(Member):一个成员是类或者对象的组成部分。成员可以是各种方法和变量,以及更多编程语言(或者GObject库)提供的功能,比如属性等。

公开成员(Public Member):如果一个对象的成员是公开的,那么你(以及其他对象)就可以访问这个成员(比如说,读取和修改一个公开变量的值,调用一个公开方法)。公开成员是与对象互动的唯一途径。

隐私成员(Private Member):如果一个对象的成员是隐私的,那么只有这个对象能修改或访问,你(以及其他对象)不能接触到他的隐私。如果开发者害怕修改一个变量或者调用一个函数会造成不可预料的行为,他就可以把这些成员作为隐私成员,藏在对象的内部,这样就不会让外人干扰对象的正常运行。(一些编程语言有更细节的成员所有权控制,这里不赘述了)

构造器(Constructor):一个对象被创造出来(实例化)时,要对这个对象做一些操作,比如说为成员变量赋初始值。在很多编程语言中,构造器是一个可以被调用的函数,可以看作是「构造函数」把对象制作出来了。

解构器(Destructor):与构造器相对的,当一个对象被删除的时候,需要做一些操作,比如释放一些成员的内存。

继承(Inheritance):通过在一个类上添加一些其他的成员来定义一个新的类,这个做法叫继承。通过继承创造出来的类就称为派生类(Derived Class),而原本的类我们叫基类(Base Class)。这样,我们可以知道,派生类拥有基类的所有成员,因此派生类的对象完全可以作为基类的对象去使用。甚至我们可以说,派生类的对象也属于基类。(举个例子:一只喜鹊既是鸟,也是动物,还是生物。而生物、动物、鸟和喜鹊,这些概念是逐渐缩小的。)

(插播一条冷笑话:曹操研究过面向对象编程,后来他说了一句名言:基类!基类!)

抽象方法(Abstract Method):定义在类中,只告诉你,这个方法是干什么的,输入参数和返回值(像是C语言中只声明不定义),但是挖坑不填,如果你继承了这个类,你就要在派生类里把这个方法写好,这样调用他才能有效果。如果把派生类的对象作为基类使用,调用抽象方法的话,其实调用的是那个派生类的。包含抽象方法的类是专门被继承的,不能直接实例化,称为抽象类(Abstract Class)。改写抽象方法和拟方法的操作叫覆盖(override)。

拟方法(Virtual Class):可以在派生类中,被改写的方法。但是和抽象方法不同的是,他有最初定义。因此不覆盖也可以使用。

接口(Interface):这个概念不只是面向对象的专属,在其他地方也有应用,比如说UI、API、ABI、音频接口(俗称声卡)、电路接口等等。在面向对象编程中,一个接口其实是一种协议或者标准,他和一种行为是相关的。如果一个类能够包含这个接口所要求的所有方法(抽象方法),他就满足了这个接口的要求,称为实现(implement)了这个接口。这时这个类的对象就可以作为这种统一的接口去使用。接口与继承关系不同的是,接口只有抽象方法,你得自己把方法写一遍;但是继承的话你就能完全获得基类的所有遗产。(举个例子:喜鹊属于鸟,飞蛾属于虫,蝙蝠属于哺乳动物,飞机属于交通工具,他们虽然不是一类的,但是他们都有飞的功能。可以说他们都实现了飞的接口。)

属性(Property):表面是变量,实际是方法。给属性赋值时,他会调用一个专用的set方法,对传入的参数进行处理后再赋值给一个隐私变量。读取属性时,会调用一个专门的get方法,给隐私变量处理后再返回。这种get/set机制,很适合使用到你希望变量不要越过一个取值范围,或者想用多种方式操作一个变量的时候。

闭包(Closure):存储到变量里的方法及其运行环境。这个方法可以交给其他对象使用来影响自己。闭包里的方法叫回调(Callback)方法。如果没有运行环境,只是个单独的函数指针,也可以叫回调方法。

信号(Signal):把闭包或者回调方法交给他(称为连接connect),在某些情况时,程序会激活这个信号(称为发射emit),这时回调方法就会被执行。信号是一种对象系统的消息传递机制。

命名空间(Namespace):一个程序中可能有许多不同开发者创作的部分,为了防止他们创造的类或者其他组件相互重名造成麻烦,把同一模块的类再取一个名字,表示这个类和其他类不属于同一个部分。这样的一个部分就是命名空间。一个命名空间的类和另一个命名空间的类即使重名,也可以通过区别命名空间来区分他们。如果命名空间重名了呢?那就只能改名了。

在下一篇文章中,我将简要介绍一些GObject对这些功能的实现方式及其特性。

Reply Favorite View the author
All Replies
阿尼樱奈奈
Moderator
2023-08-10 15:04
#1

applaud

Reply View the author
wlly-lzh
deepin
2023-08-10 15:35
#2

c语言理论上可以实现面向对象,可以通过struct和一些函数来实现,但是比直接使用支持面向对象的语言要复杂。joy 我自己曾这样构想过,不过没有实践过。joy

Reply View the author
方老四
deepin
2023-08-10 17:01
#3

对于底层的操作,面向对像用处不大,对于构建大型应用会有更高的效率

Reply View the author
fuuko
deepin
2023-08-10 18:26
#4

所以咱能直接用C++么?或者Rust也行doubt

Reply View the author
fuuko
deepin
2023-08-10 18:28
#5
wlly-lzh

c语言理论上可以实现面向对象,可以通过struct和一些函数来实现,但是比直接使用支持面向对象的语言要复杂。joy 我自己曾这样构想过,不过没有实践过。joy

C语言啥都可以模拟,但会很痛苦doubt

GObject就是glib的底座之一,而glib是GTK、GStreamer等库的底座doubt

这个玩意儿的特色就是用C语言强行搞定了面向对象doubt

Reply View the author