前言:
众所周知,C语言是一门面向过程的语言,但是不代表就得跟面向对象完全绝缘,在C语言库glib中有gobject那么一套面向对象的机制,基于C语言的面向对象设计便是基于该实现机制。
今天所要实践的便是面向对象的一个重要特征:抽象与继承
笔者的水平有限,如果文章有什么错误的地方还望指出。
1、设计说明
开发语言:C语言
基础库:glib
设计目的:简要设计类来实现抽象与继承
2、由几个有相同属性或操作的类抽象出一个父类。
这里简单使用gobject的一套设计模板,细节部分不做说明,有研究兴趣的读者可以研究一下。
父类:base(该类由base.h和base.c共同组成)
base.h
1 #ifndef __BASE_H__ 2 #define __BASE_H__ 3 4 #include <glib.h> 5 #include <stdio.h> 6 #include <glib-object.h> 7 G_BEGIN_DECLS 8 9 #define BASE_TYPE (base_get_type ())//该对象的类型 10 #define BASE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BASE_TYPE, Base))//类型转换,转换为该对象的类型 11 #define BASE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BASE_TYPE, BaseClass)) 12 #define IS_BASE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BASE_TYPE)) 13 #define IS_BASE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BASE_TYPE)) 14 #define BASE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BASE_TYPE, BaseClass)) 15 #define BASE_CAST(obj) ((Base*)(obj)) 16 17 18 typedef struct _Base Base; 19 typedef struct _BaseClass BaseClass; 20 typedef struct _BasePrivate BasePrivate; 21 22 23 struct _Base 24 { 25 GObject parent; 26 //设置共有变量,提供给子类访问 27 GString *str; 28 }; 29 30 struct _BaseClass 31 { 32 GObjectClass parentclass; 33 //设置设置写和读名字的方法,由子类重载 34 void (*showKill)(Base *self); 35 char *(*getSkill)(Base *self); 36 }; 37 38 GType base_get_type (void); 39 //这些方法被子类所共有,其中skill的操作方法需要由子类重载。 40 void base_set_name(Base *self,char *name); 41 char * base_get_name(Base *self); 42 void base_show_skill(Base *self); 43 char * base_get_skill(Base *self); 44 45 G_END_DECLS 46 47 48 49 #endif /* ABSTRACTMODEL_H_ */
basec.c
1 #include "base.h" 2 #include <string.h> 3 4 //父类即抽象类的宏定义,继承自object 5 G_DEFINE_ABSTRACT_TYPE(Base, base, G_TYPE_OBJECT); 6 7 #define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BASE_TYPE, Base)) 8 9 struct _BasePrivate 10 { 11 char *name; 12 }; 13 14 static void dispose_od(GObject *object); 15 static void finalize_od(GObject *object); 16 17 static void base_class_init(BaseClass *klass) 18 { 19 GObjectClass *object_class = G_OBJECT_CLASS(klass); 20 g_type_class_add_private(klass, sizeof(BasePrivate)); 21 object_class->dispose = dispose_od; 22 object_class->finalize = finalize_od; 23 } 24 25 static void base_init(Base *self) 26 { 27 BasePrivate *priv = GET_PRIVATE(self); 28 self->str = g_string_new("暴露出来给你们访问的"); 29 } 30 static void dispose_od(GObject *object) 31 { 32 Base *self = BASE(object); 33 BasePrivate *priv = GET_PRIVATE(self); 34 if(self->str) 35 { 36 g_string_free(self->str,TRUE); 37 self->str=NULL; 38 } 39 G_OBJECT_CLASS(base_parent_class)->dispose(object); 40 } 41 42 static void finalize_od(GObject *object) 43 { 44 Base *self = BASE(object); 45 BasePrivate *priv = GET_PRIVATE(self); 46 47 G_OBJECT_CLASS(base_parent_class)->finalize(object); 48 } 49 50 void base_set_name(Base *self,char *name) 51 { 52 BasePrivate *priv = GET_PRIVATE(self); 53 priv->name = strdup(name); 54 } 55 char *base_get_name(Base *self) 56 { 57 BasePrivate *priv = GET_PRIVATE(self); 58 return priv->name; 59 } 60 61 void base_show_skill(Base *self) 62 { 63 if (self) 64 { 65 BaseClass *baseClass = BASE_GET_CLASS(self); 66 baseClass->showKill(self); 67 } 68 } 69 char * base_get_skill(Base *self) 70 { 71 char *skill = NULL; 72 if (self) 73 { 74 BaseClass *baseClass = BASE_GET_CLASS(self); 75 skill = baseClass->getSkill(self); 76 } 77 return skill; 78 }
子类1:(由文件subbase1.h和subbase.c组成)
subbase1.h
1 #ifndef __SUBBASE1_H__ 2 #define __SUBBASE1_H__ 3 4 #include <glib.h> 5 #include <stdio.h> 6 #include <glib-object.h> 7 #include"base.h" 8 G_BEGIN_DECLS 9 10 #define SUBBASE1_TYPE (subbase1_get_type ())//该对象的类型 11 #define SUBBASE1(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SUBBASE1_TYPE, Subbase1))//类型转换,转换为该对象的类型 12 #define SUBBASE1_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SUBBASE1_TYPE, Subbase1Class)) 13 #define IS_SUBBASE1(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SUBBASE1_TYPE)) 14 #define IS_SUBBASE1_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SUBBASE1_TYPE)) 15 #define SUBBASE1_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SUBBASE1_TYPE, Subbase1Class)) 16 #define SUBBASE1_CAST(obj) ((Subbase1*)(obj)) 17 18 19 typedef struct _Subbase1 Subbase1; 20 typedef struct _Subbase1Class Subbase1Class; 21 typedef struct _Subbase1Private Subbase1Private; 22 23 24 struct _Subbase1 25 { 26 Base parent; 27 }; 28 29 struct _Subbase1Class 30 { 31 BaseClass parentclass; 32 }; 33 34 GType subbase1_get_type (void); 35 Subbase1* subbase1_new(void); 36 void subbase1_sing_song(Subbase1 *self,char *song); 37 38 G_END_DECLS 39 #endif /* ABSTRACTMODEL_H_ */
subbase1.c
1 #include "subbase1.h" 2 #include <string.h> 3 4 //子类的宏定义,继承父类类型 5 G_DEFINE_TYPE(Subbase1, subbase1, BASE_TYPE); 6 7 #define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SUBBASE1_TYPE, Subbase1)) 8 9 struct _Subbase1Private 10 { 11 }; 12 13 static void dispose_od(GObject *object); 14 static void finalize_od(GObject *object); 15 static char *getSkill_od(Base *self); 16 static void showKill_od(Base *self); 17 static void subbase1_class_init(Subbase1Class *klass) 18 { 19 GObjectClass *object_class = G_OBJECT_CLASS(klass); 20 g_type_class_add_private(klass, sizeof(Subbase1Private)); 21 object_class->dispose = dispose_od; 22 object_class->finalize = finalize_od; 23 BaseClass *baseClass = BASE_CLASS(klass); 24 baseClass->getSkill =getSkill_od; 25 baseClass->showKill = showKill_od; 26 27 } 28 29 static void subbase1_init(Subbase1 *self) 30 { 31 Subbase1Private *priv = GET_PRIVATE(self); 32 } 33 static void dispose_od(GObject *object) 34 { 35 Subbase1 *self = SUBBASE1(object); 36 Subbase1Private *priv = GET_PRIVATE(self); 37 38 G_OBJECT_CLASS(subbase1_parent_class)->dispose(object); 39 } 40 41 static void finalize_od(GObject *object) 42 { 43 Subbase1 *self = SUBBASE1(object); 44 Subbase1Private *priv = GET_PRIVATE(self); 45 46 G_OBJECT_CLASS(subbase1_parent_class)->finalize(object); 47 } 48 static char *getSkill_od(Base *self) 49 { 50 return "sing"; 51 } 52 static void showKill_od(Base *self) 53 { 54 g_print("I singing! "); 55 } 56 57 Subbase1* subbase1_new(void) 58 { 59 Subbase1 *res = g_object_new(SUBBASE1_TYPE,NULL); 60 return res; 61 62 } 63 void subbase1_sing_song(Subbase1 *self,char *song) 64 { 65 g_print("I singing a song for name is %s! ",song); 66 }
子类2:(由subbase2.h和subbase2.c文件组成)
subbase2.h
1 #ifndef __SUBBASE2_H__ 2 #define __SUBBASE2_H__ 3 4 #include <glib.h> 5 #include <stdio.h> 6 #include <glib-object.h> 7 #include"base.h" 8 G_BEGIN_DECLS 9 10 #define SUBBASE2_TYPE (subbase2_get_type ())//该对象的类型 11 #define SUBBASE2(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SUBBASE2_TYPE, Subbase2))//类型转换,转换为该对象的类型 12 #define SUBBASE2_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SUBBASE2_TYPE, Subbase2Class)) 13 #define IS_SUBBASE2(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SUBBASE2_TYPE)) 14 #define IS_SUBBASE2_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SUBBASE2_TYPE)) 15 #define SUBBASE2_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SUBBASE2_TYPE, Subbase2Class)) 16 #define SUBBASE2_CAST(obj) ((Subbase2*)(obj)) 17 18 19 typedef struct _Subbase2 Subbase2; 20 typedef struct _Subbase2Class Subbase2Class; 21 typedef struct _Subbase2Private Subbase2Private; 22 23 24 struct _Subbase2 25 { 26 Base parent; 27 }; 28 29 struct _Subbase2Class 30 { 31 BaseClass parentclass; 32 }; 33 34 GType subbase2_get_type (void); 35 Subbase2 * subbase2_new(void); 36 void subbase2_dance_dance(Subbase2 *self,char *dance); 37 38 G_END_DECLS 39 #endif /* ABSTRACTMODEL_H_ */
subbase2.c
1 #include "subbase2.h" 2 #include <string.h> 3 4 //子类的宏定义,继承父类类型 5 G_DEFINE_TYPE(Subbase2, subbase2, BASE_TYPE); 6 7 #define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SUBBASE2_TYPE, Subbase2)) 8 9 struct _Subbase2Private 10 { 11 }; 12 13 static void dispose_od(GObject *object); 14 static void finalize_od(GObject *object); 15 static void showSkill_od(Base *self); 16 static char *getSkill_od(Base *self); 17 18 static void subbase2_class_init(Subbase2Class *klass) 19 { 20 GObjectClass *object_class = G_OBJECT_CLASS(klass); 21 g_type_class_add_private(klass, sizeof(Subbase2Private)); 22 object_class->dispose = dispose_od; 23 object_class->finalize = finalize_od; 24 BaseClass *baseClass = BASE_CLASS(klass); 25 baseClass->getSkill=getSkill_od; 26 baseClass->showKill=showSkill_od; 27 } 28 29 static void subbase2_init(Subbase2 *self) 30 { 31 Subbase2Private *priv = GET_PRIVATE(self); 32 } 33 34 static void dispose_od(GObject *object) 35 { 36 Subbase2 *self = SUBBASE2(object); 37 Subbase2Private *priv = GET_PRIVATE(self); 38 39 G_OBJECT_CLASS(subbase2_parent_class)->dispose(object); 40 } 41 42 static void finalize_od(GObject *object) 43 { 44 Subbase2 *self = SUBBASE2(object); 45 Subbase2Private *priv = GET_PRIVATE(self); 46 47 G_OBJECT_CLASS(subbase2_parent_class)->finalize(object); 48 } 49 static void showSkill_od(Base *self) 50 { 51 g_print("I ' m dancing "); 52 } 53 static char *getSkill_od(Base *self) 54 { 55 return "dance"; 56 } 57 58 Subbase2 * subbase2_new(void) 59 { 60 Subbase2 *res = g_object_new(SUBBASE2_TYPE,NULL); 61 return res; 62 } 63 void subbase2_dance_dance(Subbase2 *self,char *dance) 64 { 65 g_print("I ' m dancing a %s dance! ",dance); 66 }
测试文件:main.c
1 #include<glib.h> 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include"base.h" 5 #include"subbase1.h" 6 #include"subbase2.h" 7 #include<string.h> 8 9 int main(void) 10 { 11 g_print("hell world! "); 12 Subbase1 *test1 = subbase1_new(); 13 Subbase1 *test2 = subbase1_new(); 14 Subbase2 *test3 = subbase2_new(); 15 16 base_set_name(BASE(test1),"test1"); 17 base_set_name(BASE(test2),"test2"); 18 base_set_name(BASE(test3),"test3"); 19 20 g_print("name:%s ",base_get_name(BASE(test1))); 21 g_print("name:%s ",base_get_name(BASE(test2))); 22 g_print("name:%s ",base_get_name(BASE(test3))); 23 24 g_print("skill:%s ",base_get_skill(BASE(test1))); 25 base_show_skill(BASE(test1)); 26 g_print("skill:%s ", base_get_skill(BASE(test3))); 27 base_show_skill(BASE(test3)); 28 29 subbase1_sing_song(test1,"我怀恋的"); 30 subbase2_dance_dance(test3,"芭蕾"); 31 32 BASE(test1)->str = g_string_new("one"); 33 g_print("%s ",BASE(test1)->str->str); 34 35 return EXIT_SUCCESS; 36 }
3、总结
如2的代码所示,其中涉及到了抽象、继承、重载等概念,C语言要使用面向对象来设计和解决问题,那么关于面向对象一般的基本特征也要了解和实现,要充分将这些实现方式转化为经验,这样再以后的面向对象设计中才能
驾轻就熟,也会更有效率。
同时如大家所见,C语言要实现面向对象这一特征是较为复杂的,代码相对JAVA或python等也非常的多,但是在嵌入式或一些需要使用C语言来设计和解决问题的领域,使用面向对象设计是有着很大的好处的,其中最明显的就是
可以减轻设计的复杂度。
4、题外话
在嵌入式领域C++的比重越来越来越大,著名的QT、openCV(一部分)等都是由C语言开发,C++开发嵌入式应用的效率上是有优势的,但是大部分的底层库还是得由C语言来实现,尤其是一些核心的东西需要C语言来支持
。