简介
面向对象编程语言 (如 C++、Java) 把数据和对数据的操作封装在一起构成类,由类来产生对象,由对象来构建程序。通过继承、重载、多态等机制大大增强软件的可重用性和可维护性。C语言虽然不是面向对象语言,但GTK+以及建立在其上的GNOME库却使C语言模拟出了一些典型的面向对象机制,如封装、继承和多态。本文详细介绍了它们的实现方法。
结构、函数指针与类
对象的一个重要特性是将数据和对数据的操作封装在一起,受保护的私有数据只能通过成员函数才能访问和修改。GTK+ 使用 C 语言的结构体来模拟对象。一个结构体就可以看成一个类,结构体里的数据成员就是类的成员变量,结构体里的函数指针变量就是类的成员函数。用这个结构体定义的一个变量可以看成一个对象。这样类和对象就基本实现了。
举个例子,下面的结构 GTKObjectClass 就可以看成一个类,其中 flag 是成员变量,三个函数指针是成员函数。
struct _GtkObjectClass
{
guint32 flag;
void (*set_arg) (GtkObject *object, GtkArg *arg, guint arg_id);
void (*get_arg) (GtkObject *object, GtkArg *arg, guint arg_id);
void (*destroy) (GtkObject *object);
};
结构体成员与继承
有了对象作为基础,通过在对象中加入新的数据和对这些数据进行操作的函数,就实现了继承。被继承的类称为父类或基类,由基础类派生出来的类称为子类或派生类。子类继承了父类的数据和对这些数据进行操作的成员函数,并加入了新的数据和成员函数,实现了对原有父类的重用和扩展,从而实现了可重用性和可扩展性。
之前提到,我们用 C 语言的结构当作面向对象中的类,子类继承了父类的成员变量和成员函数,那么,我们让每一个子类所在的结构体都包含一个父类的结构体,子类结构体的第一个成员是其父类结构体,那么子类就继承了父类的成员,由此就实现了继承。
举个例子,GTK+ 中有一个类 GtkObject,它是所有其他类的父类。GTK+ 中最常
用的按钮控件也是一个类 GtkButton,它继承自 GtkObject。它与 GtkObject
的继承关系是:
GtkObject->GtkWidget->GtkContainer->GtkBin->GtkButton
它们在 GTK+ 的实现如下所示:
struct GtkObject {
......
}
struct Widget {
GtkObject object;
......
}
struct GtkContainer {
GtkWidget widget;
......
};
struct GtkBin {
GtkContainer container;
......
};
struct GtkButton {
GtkBin bin;
......
};
强制类型转换与多态性
多态性,用一个经典的英文解释就是 a value can belong to multiple types,即一个值属于多种类型。在面向对象语言语言中,一个对象可能属于一个子类,同时也属于该子类的父类,如,在 C++ 中经常用到这样的定义:
ParentClass A = new ChildClass ();
对象 A 既属于子类,也属于父类。
在 C 语言中,可以使用指针的强制类项转换来实现多态性,,但要求父类结构
体数据必须位于子类结构体的开始。比如,对于一个GtkButton 类型的button控
件变量 (它其实是一个指向 GtkButton 结构体的指针),通过宏
GTKBIN(button) 就得到了其父类 ( GTK+ 预定义的宏 GTKBIN 其实是进行了强
制类型转换,把一个 GtkButton 类型的指针强制转化为 GtkBin 类型的指针)。
以创建一个 Button Widget 为例,如下所示:
GtkWidget *button;
button = gtk_button_new_with_label ("Hello World");
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (hello), NULL);
button 声明为 GtkWidget 类型的指针,用 gtk_button_new_with_lable 创建
一个 GtkButton;G_OBJECT 是一个宏,完成强制类型转换,这里将
button 从 GtkWidget 类型转换成 GObject 类型。
Reference
http://book.csdn.net/bookfiles/645/10064520529.shtml
|