glib实践篇:父类与子类
前言:
众所周知,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实践篇:父类与子类的更多相关文章
- Java特性之多态父类与子类之间的调用
问题描述: Java三大特性,封装.继承.多态,一直没搞懂其中多态是什么,最近研究了一下,关于父类和子类之间的调用.下面是一个测试类,源代码如下: package com.test; public c ...
- java中父类与子类, 不同的两个类中的因为构造函数由于递归调用导致栈溢出问题
/* 对于类中对成员变量的初始化和代码块中的代码全部都挪到了构造函数中, 并且是按照java源文件的初始化顺序依次对成员变量进行初始化的,而原构造函数中的代码则移到了构造函数的最后执行 */ impo ...
- java父类转子类的一个方法
一般子类可以转父类.但父类转子类就会报cast error. 使用jsonobject 思想:先把父类转jsonstring 再把jsonstring转子类.剩余的子类值可以设定进去. import ...
- P188 实战练习(父类和子类)
1.创建一个父类,在父类中创建两个方法,在子类中覆盖第二个方法,为子类创建一个对象,将它向上转型到基类并调用这个方法. 创建Computer父类: package org.hanqi.practise ...
- 20141214--C#父类,子类
首要: 子类 包含父类的所有的属性方法 所有子类都可以直接转化成父类类型 当父类类型变量里面存的是某个子类的对象的时候,才能转化成那个子类类型. 父类与子类的装换: Ren r = new Ren() ...
- 多态&&父类调用子类特有的方法
/* 多态 1.没有继承就没有多态 2.代码的体现:父类类型的指针指向子类对象 3.好处:如果函数\方法参数使用的是父类对象,可以传入父类.子类对象 4.局限性: 1>父类类型的变量,不能直接调 ...
- C#基础知识—父类和子类的关系
基础知识一: using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms ...
- php 父类调用子类方法和成员
在C和C++里,父类都不允许调用子类的方法,但在php里可以.下面是一个调用的例子: <?php abstract class Animal { protected $name; public ...
- Java 多态 父类和子类方法的访问控制权限
Java 多态 父类和子类方法的访问控制权限 @author ixenos 父类和子类方法的访问控制权限 继承是为了扩展类的功能,而这种扩展显然就是对一个原始类的扩展,目的还是向上转型来调用,所以这就 ...
- c++ --> 父类与子类间的继承关系
父类与子类间的继承关系 一.父类与子类 父类与子类的相互转换 1.派生类的对象可以赋给基类,反之不行 2.基类的指针可以指向派生类,反之不行 3.基类的引用可以初始化为派生类的对象,反之不行 4.派生 ...
随机推荐
- ASP.NET MVC应用程序使用异步及存储过程
ASP.NET MVC应用程序使用异步及存储过程 是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译 ...
- iOS基础 - 数据库CoreData
一.iOS应用数据存取的常用方式 XML属性列表 —— PList NSKeyedArchiver 归档 Preference(偏好设置) SQLite3 Core Data 二.Core Data简 ...
- 2 MySQL安装
目录: 1. mysql安装简介2. 下载AppServ3. 安装AppServ4. 使用phpmyadmin连接MySQL5. 使用MySQL Command Line Client 连接MySQL ...
- 常用oracle语句-------------------------------------------》(笔记)
Orale常用语句 1:查询指定表名的字段 select * from sys.user_tab_columns where table_name=表名 //查询指定表名的字段 2: 查询数据库参 ...
- 强制卸载VS2013
最近因为VS2013闹许可证过期问题,加之又发现新版本update5,所以就想卸掉重装,但是按照正常的卸载,发现卸载不了,再后来force强制卸载,OK了. force强制卸载: 首先如果安装了中文包 ...
- C语言的一些常见细节
C语言的一些常见细节 对于C语言,不同的编译器采用了不同的实现,并且在不同平台上表现也不同.脱离具体环境探讨C的细节行为是没有意义的,以下是我所使用的环境,大部分内容都经过测试,且所有测试结果基于这个 ...
- 使用 Entity Framework Code First
使用 Entity Framework Code First 在家闲着也是闲着,继续写我的[ASP.NET MVC 小牛之路]系列吧.在该系列的上一篇博文中,在显示书本信息列表的时候,我们是在程序代码 ...
- 【ADO.Excel】ADO获取excel的Sheet集合
using (OleDbConnection connection = new OleDbConnection(GetConnectionString())) { connection.Open(); ...
- PyQt设计流程
Qt designer 设计流程: 创建一个 PyQt4 的步骤,通常的方法是用 QtDesigner 工具创建 GUI 界面.可以在窗口 上添加部件,并可以对部件进行一些属性配置.一般的过程如下 ...
- Linux 内核源码中likely()和unlikely()
ikely()与unlikely()在2.6内核中,随处可见,那为什么要用它们?它们之间有什么区别呢? 首先明确: if (likely(value))等价于if (value)if (likely( ...