前言:

  众所周知,C语言是一门面向过程的语言,但是不代表就得跟面向对象完全绝缘,在C语言库glib中有gobject那么一套面向对象的机制,基于C语言的面向对象设计便是基于该实现机制。

  今天所要实践的便是面向对象的一个重要特征:抽象与继承

  笔者的水平有限,如果文章有什么错误的地方还望指出。

1、设计说明

  开发语言:C语言

  基础库:glib

  设计目的:简要设计类来实现抽象与继承

2、由几个有相同属性或操作的类抽象出一个父类。

  这里简单使用gobject的一套设计模板,细节部分不做说明,有研究兴趣的读者可以研究一下。

  父类:base(该类由base.h和base.c共同组成)

  base.h

 #ifndef __BASE_H__
#define __BASE_H__ #include <glib.h>
#include <stdio.h>
#include <glib-object.h>
G_BEGIN_DECLS #define BASE_TYPE (base_get_type ())//该对象的类型
#define BASE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BASE_TYPE, Base))//类型转换,转换为该对象的类型
#define BASE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BASE_TYPE, BaseClass))
#define IS_BASE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BASE_TYPE))
#define IS_BASE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BASE_TYPE))
#define BASE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BASE_TYPE, BaseClass))
#define BASE_CAST(obj) ((Base*)(obj)) typedef struct _Base Base;
typedef struct _BaseClass BaseClass;
typedef struct _BasePrivate BasePrivate; struct _Base
{
GObject parent;
//设置共有变量,提供给子类访问
GString *str;
}; struct _BaseClass
{
GObjectClass parentclass;
//设置设置写和读名字的方法,由子类重载
void (*showKill)(Base *self);
char *(*getSkill)(Base *self);
}; GType base_get_type (void);
//这些方法被子类所共有,其中skill的操作方法需要由子类重载。
void base_set_name(Base *self,char *name);
char * base_get_name(Base *self);
void base_show_skill(Base *self);
char * base_get_skill(Base *self); G_END_DECLS #endif /* ABSTRACTMODEL_H_ */

basec.c

 #include "base.h"
#include <string.h> //父类即抽象类的宏定义,继承自object
G_DEFINE_ABSTRACT_TYPE(Base, base, G_TYPE_OBJECT); #define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BASE_TYPE, Base)) struct _BasePrivate
{
char *name;
}; static void dispose_od(GObject *object);
static void finalize_od(GObject *object); static void base_class_init(BaseClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
g_type_class_add_private(klass, sizeof(BasePrivate));
object_class->dispose = dispose_od;
object_class->finalize = finalize_od;
} static void base_init(Base *self)
{
BasePrivate *priv = GET_PRIVATE(self);
self->str = g_string_new("暴露出来给你们访问的");
}
static void dispose_od(GObject *object)
{
Base *self = BASE(object);
BasePrivate *priv = GET_PRIVATE(self);
if(self->str)
{
g_string_free(self->str,TRUE);
self->str=NULL;
}
G_OBJECT_CLASS(base_parent_class)->dispose(object);
} static void finalize_od(GObject *object)
{
Base *self = BASE(object);
BasePrivate *priv = GET_PRIVATE(self); G_OBJECT_CLASS(base_parent_class)->finalize(object);
} void base_set_name(Base *self,char *name)
{
BasePrivate *priv = GET_PRIVATE(self);
priv->name = strdup(name);
}
char *base_get_name(Base *self)
{
BasePrivate *priv = GET_PRIVATE(self);
return priv->name;
} void base_show_skill(Base *self)
{
if (self)
{
BaseClass *baseClass = BASE_GET_CLASS(self);
baseClass->showKill(self);
}
}
char * base_get_skill(Base *self)
{
char *skill = NULL;
if (self)
{
BaseClass *baseClass = BASE_GET_CLASS(self);
skill = baseClass->getSkill(self);
}
return skill;
}

  子类1:(由文件subbase1.h和subbase.c组成)

  subbase1.h

 #ifndef __SUBBASE1_H__
#define __SUBBASE1_H__ #include <glib.h>
#include <stdio.h>
#include <glib-object.h>
#include"base.h"
G_BEGIN_DECLS #define SUBBASE1_TYPE (subbase1_get_type ())//该对象的类型
#define SUBBASE1(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SUBBASE1_TYPE, Subbase1))//类型转换,转换为该对象的类型
#define SUBBASE1_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SUBBASE1_TYPE, Subbase1Class))
#define IS_SUBBASE1(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SUBBASE1_TYPE))
#define IS_SUBBASE1_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SUBBASE1_TYPE))
#define SUBBASE1_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SUBBASE1_TYPE, Subbase1Class))
#define SUBBASE1_CAST(obj) ((Subbase1*)(obj)) typedef struct _Subbase1 Subbase1;
typedef struct _Subbase1Class Subbase1Class;
typedef struct _Subbase1Private Subbase1Private; struct _Subbase1
{
Base parent;
}; struct _Subbase1Class
{
BaseClass parentclass;
}; GType subbase1_get_type (void);
Subbase1* subbase1_new(void);
void subbase1_sing_song(Subbase1 *self,char *song); G_END_DECLS
#endif /* ABSTRACTMODEL_H_ */

  subbase1.c

 #include "subbase1.h"
#include <string.h> //子类的宏定义,继承父类类型
G_DEFINE_TYPE(Subbase1, subbase1, BASE_TYPE); #define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SUBBASE1_TYPE, Subbase1)) struct _Subbase1Private
{
}; static void dispose_od(GObject *object);
static void finalize_od(GObject *object);
static char *getSkill_od(Base *self);
static void showKill_od(Base *self);
static void subbase1_class_init(Subbase1Class *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
g_type_class_add_private(klass, sizeof(Subbase1Private));
object_class->dispose = dispose_od;
object_class->finalize = finalize_od;
BaseClass *baseClass = BASE_CLASS(klass);
baseClass->getSkill =getSkill_od;
baseClass->showKill = showKill_od; } static void subbase1_init(Subbase1 *self)
{
Subbase1Private *priv = GET_PRIVATE(self);
}
static void dispose_od(GObject *object)
{
Subbase1 *self = SUBBASE1(object);
Subbase1Private *priv = GET_PRIVATE(self); G_OBJECT_CLASS(subbase1_parent_class)->dispose(object);
} static void finalize_od(GObject *object)
{
Subbase1 *self = SUBBASE1(object);
Subbase1Private *priv = GET_PRIVATE(self); G_OBJECT_CLASS(subbase1_parent_class)->finalize(object);
}
static char *getSkill_od(Base *self)
{
return "sing";
}
static void showKill_od(Base *self)
{
g_print("I singing!\n");
} Subbase1* subbase1_new(void)
{
Subbase1 *res = g_object_new(SUBBASE1_TYPE,NULL);
return res; }
void subbase1_sing_song(Subbase1 *self,char *song)
{
g_print("I singing a song for name is %s!\n",song);
}

  子类2:(由subbase2.h和subbase2.c文件组成)

  subbase2.h

 #ifndef __SUBBASE2_H__
#define __SUBBASE2_H__ #include <glib.h>
#include <stdio.h>
#include <glib-object.h>
#include"base.h"
G_BEGIN_DECLS #define SUBBASE2_TYPE (subbase2_get_type ())//该对象的类型
#define SUBBASE2(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SUBBASE2_TYPE, Subbase2))//类型转换,转换为该对象的类型
#define SUBBASE2_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SUBBASE2_TYPE, Subbase2Class))
#define IS_SUBBASE2(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SUBBASE2_TYPE))
#define IS_SUBBASE2_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SUBBASE2_TYPE))
#define SUBBASE2_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SUBBASE2_TYPE, Subbase2Class))
#define SUBBASE2_CAST(obj) ((Subbase2*)(obj)) typedef struct _Subbase2 Subbase2;
typedef struct _Subbase2Class Subbase2Class;
typedef struct _Subbase2Private Subbase2Private; struct _Subbase2
{
Base parent;
}; struct _Subbase2Class
{
BaseClass parentclass;
}; GType subbase2_get_type (void);
Subbase2 * subbase2_new(void);
void subbase2_dance_dance(Subbase2 *self,char *dance); G_END_DECLS
#endif /* ABSTRACTMODEL_H_ */

  subbase2.c

 #include "subbase2.h"
#include <string.h> //子类的宏定义,继承父类类型
G_DEFINE_TYPE(Subbase2, subbase2, BASE_TYPE); #define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SUBBASE2_TYPE, Subbase2)) struct _Subbase2Private
{
}; static void dispose_od(GObject *object);
static void finalize_od(GObject *object);
static void showSkill_od(Base *self);
static char *getSkill_od(Base *self); static void subbase2_class_init(Subbase2Class *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
g_type_class_add_private(klass, sizeof(Subbase2Private));
object_class->dispose = dispose_od;
object_class->finalize = finalize_od;
BaseClass *baseClass = BASE_CLASS(klass);
baseClass->getSkill=getSkill_od;
baseClass->showKill=showSkill_od;
} static void subbase2_init(Subbase2 *self)
{
Subbase2Private *priv = GET_PRIVATE(self);
} static void dispose_od(GObject *object)
{
Subbase2 *self = SUBBASE2(object);
Subbase2Private *priv = GET_PRIVATE(self); G_OBJECT_CLASS(subbase2_parent_class)->dispose(object);
} static void finalize_od(GObject *object)
{
Subbase2 *self = SUBBASE2(object);
Subbase2Private *priv = GET_PRIVATE(self); G_OBJECT_CLASS(subbase2_parent_class)->finalize(object);
}
static void showSkill_od(Base *self)
{
g_print("I ' m dancing\n");
}
static char *getSkill_od(Base *self)
{
return "dance";
} Subbase2 * subbase2_new(void)
{
Subbase2 *res = g_object_new(SUBBASE2_TYPE,NULL);
return res;
}
void subbase2_dance_dance(Subbase2 *self,char *dance)
{
g_print("I ' m dancing a %s dance!\n",dance);
}

测试文件:main.c

 #include<glib.h>
#include<stdio.h>
#include<stdlib.h>
#include"base.h"
#include"subbase1.h"
#include"subbase2.h"
#include<string.h> int main(void)
{
g_print("hell world!\n");
Subbase1 *test1 = subbase1_new();
Subbase1 *test2 = subbase1_new();
Subbase2 *test3 = subbase2_new(); base_set_name(BASE(test1),"test1");
base_set_name(BASE(test2),"test2");
base_set_name(BASE(test3),"test3"); g_print("name:%s\n",base_get_name(BASE(test1)));
g_print("name:%s\n",base_get_name(BASE(test2)));
g_print("name:%s\n",base_get_name(BASE(test3))); g_print("skill:%s\n",base_get_skill(BASE(test1)));
base_show_skill(BASE(test1));
g_print("skill:%s\n", base_get_skill(BASE(test3)));
base_show_skill(BASE(test3)); subbase1_sing_song(test1,"我怀恋的");
subbase2_dance_dance(test3,"芭蕾"); BASE(test1)->str = g_string_new("one");
g_print("%s\n",BASE(test1)->str->str); return EXIT_SUCCESS;
}

3、总结

  如2的代码所示,其中涉及到了抽象、继承、重载等概念,C语言要使用面向对象来设计和解决问题,那么关于面向对象一般的基本特征也要了解和实现,要充分将这些实现方式转化为经验,这样再以后的面向对象设计中才能

驾轻就熟,也会更有效率。

  同时如大家所见,C语言要实现面向对象这一特征是较为复杂的,代码相对JAVA或python等也非常的多,但是在嵌入式或一些需要使用C语言来设计和解决问题的领域,使用面向对象设计是有着很大的好处的,其中最明显的就是

可以减轻设计的复杂度。

4、题外话

  在嵌入式领域C++的比重越来越来越大,著名的QT、openCV(一部分)等都是由C语言开发,C++开发嵌入式应用的效率上是有优势的,但是大部分的底层库还是得由C语言来实现,尤其是一些核心的东西需要C语言来支持

glib实践篇:父类与子类的更多相关文章

  1. Java特性之多态父类与子类之间的调用

    问题描述: Java三大特性,封装.继承.多态,一直没搞懂其中多态是什么,最近研究了一下,关于父类和子类之间的调用.下面是一个测试类,源代码如下: package com.test; public c ...

  2. java中父类与子类, 不同的两个类中的因为构造函数由于递归调用导致栈溢出问题

    /* 对于类中对成员变量的初始化和代码块中的代码全部都挪到了构造函数中, 并且是按照java源文件的初始化顺序依次对成员变量进行初始化的,而原构造函数中的代码则移到了构造函数的最后执行 */ impo ...

  3. java父类转子类的一个方法

    一般子类可以转父类.但父类转子类就会报cast error. 使用jsonobject 思想:先把父类转jsonstring 再把jsonstring转子类.剩余的子类值可以设定进去. import ...

  4. P188 实战练习(父类和子类)

    1.创建一个父类,在父类中创建两个方法,在子类中覆盖第二个方法,为子类创建一个对象,将它向上转型到基类并调用这个方法. 创建Computer父类: package org.hanqi.practise ...

  5. 20141214--C#父类,子类

    首要: 子类 包含父类的所有的属性方法 所有子类都可以直接转化成父类类型 当父类类型变量里面存的是某个子类的对象的时候,才能转化成那个子类类型. 父类与子类的装换: Ren r = new Ren() ...

  6. 多态&&父类调用子类特有的方法

    /* 多态 1.没有继承就没有多态 2.代码的体现:父类类型的指针指向子类对象 3.好处:如果函数\方法参数使用的是父类对象,可以传入父类.子类对象 4.局限性: 1>父类类型的变量,不能直接调 ...

  7. C#基础知识—父类和子类的关系

    基础知识一: using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms ...

  8. php 父类调用子类方法和成员

    在C和C++里,父类都不允许调用子类的方法,但在php里可以.下面是一个调用的例子: <?php abstract class Animal { protected $name; public ...

  9. Java 多态 父类和子类方法的访问控制权限

    Java 多态 父类和子类方法的访问控制权限 @author ixenos 父类和子类方法的访问控制权限 继承是为了扩展类的功能,而这种扩展显然就是对一个原始类的扩展,目的还是向上转型来调用,所以这就 ...

  10. c++ --> 父类与子类间的继承关系

    父类与子类间的继承关系 一.父类与子类 父类与子类的相互转换 1.派生类的对象可以赋给基类,反之不行 2.基类的指针可以指向派生类,反之不行 3.基类的引用可以初始化为派生类的对象,反之不行 4.派生 ...

随机推荐

  1. javascript call和apply

    每个函数都包含两个非继承而来的方法:call和apply. 我们可以通过这两个方法来间接调用函数.可以这样: f.call(o); f.apply(o); //o对象间接调用了f函数 这与下面的功能相 ...

  2. .net平台下socket异步通讯(代码实例)

    你应该知道的.net平台下socket异步通讯(代码实例) 1,首先添加两个windows窗体项目,一个作为服务端server,一个作为客户端Client 2,然后添加服务端代码,添加命名空间,界面上 ...

  3. Web前端开发的一点记录

    工欲善其事必先利其器,开发工具选择Sublime Text 简称(ST) 本文所说的均在Windows NT 环境下使用的ST3运行. ST的Package Control安装方法: 1. 直接输入p ...

  4. JavaWEB开发国际化

    1.国际化开发概述 )软件的国际化:软件开发时,要使它能同时应对世界不同地区和国家的访问,并针对不同地区和国家的访问,提供相应的.符合来访者阅读习惯的页面或数据. )国际化又称为 i18n:inter ...

  5. (转)poj1182食物链

    这题主要是看了http://blog.csdn.net/c0de4fun/article/details/7318642这篇解题报告,所以内容基本是转的!感谢大牛这么详细的把过程写的很清楚! 这道题目 ...

  6. thinkphp实现自动登录

    网页上经常有一些自动登录的checkbox,勾选后,下次进入该网站,无需登录,即可执行一些需要登录才能执行的操作.上班无事,用thinkphp做了下 1 下面是一个很普通的form表单,有一个chec ...

  7. windows服务1053错误排查

    公司员工离职,接手他的任务,告诉我windows服务已经完成,没来得及测试.好吧,我接着做...... 服务生成后,运行bat文件.启动服务失败,提示错误编码1053.根据以往的经验,一般是三方面引起 ...

  8. Redis系统学习 一、基础知识

    1.数据库 select 1  select 0 2.命令.关键字和值 redis不仅仅是一种简单的关键字-值型存储,从其核心概念来看,Redsi的5种数据结构中的每一个都至少有一个关键字和一个值.在 ...

  9. 利用HttpWebRequest和HttpWebResponse获取Cookie并实现模拟登录

    利用HttpWebRequest和HttpWebResponse获取Cookie并实现模拟登录 tring cookie = response.Headers.Get("Set-Cookie ...

  10. POJ 3348 Cows

    题目大意: 给你n棵树,可以用这n棵树围一个圈,然后在圈里面可以养牛,每个牛需要50平方米的空间,问最多可以养多少牛? 其实就是求一个凸包,计算凸包面积,然后除以50,然后就得到答案,直接上模板了. ...