C语言本身是不支持继承和多态的,但其实在 C 的世界里,有一套非常有名的面向对象的框架,用的也非常广,那就是 GObject,它是整个图形界面开发库 GTK 的基石,在IBM developerWorks上有一篇很好的文章介绍 GObject《GObject对象系统》。另外,在 Linux 内核里面也大量使用了面向对象的思想,比如虚拟文件系统,设备驱动等模块,在 lwn上有两篇文章就讲到了内核中的面向对象,详细请看:《Object oriented design patterns in the kernel, part 1》,《Object oriented design patterns in the kernel, part 2》。

  c语言里继承和多态的实现主要通过函数指针来实现,现在我们就来动手实现C语言的继承与多态,我们以比较经典的动物世界中的实例来举例:假设动物们(包括人)都会吃(Eat),会走(Walk),会说(Talk),而派生类为 dog(汪星人) 和 cat(喵星人),当然还可以是更多,dog 和 cat 都有自己独特的 eat, walk 和 talk 方式,那么大致的代码如下:

基类代码 animal-base.h|c:

/*
* =============================================================================
*
* Filename: animal-base.h
*
* Description: animal base class.
*
*
* =============================================================================
*/
#ifndef _ANIMAL_H_
#define _ANIMAL_H_ typedef struct animal_s_ animal_t;
typedef struct animal_ops_s_ animal_ops_t; /* 动物类,是所有动物类的基类,也是抽象类 */
struct animal_s_ {
char *name; /*< 动物的名称 */
animal_ops_t *animal_ops; /* 动物的基本行为 */
}; /* 动物的基本行为 */
struct animal_ops_s_ {
/* 动物吃了什么食物 */
void (*eat)(char *food);
/* 动物走了多少步 */
void (*walk)(int steps);
/* 动物在说什么 */
void (*talk)(char *msg);
}; /* 基类的构造函数,需要显示调用 */
extern animal_t * animal_init(char *name); /* 基类的有关操作,如吃,走,说等等 */
extern void animal_eat(animal_t *animal, char *food);
extern void animal_walk(animal_t *animal, int steps);
extern void animal_talk(animal_t *animal, char *msg); /* 基类的析构函数,需要显示调用 */
extern void animal_die(animal_t *animal); #endif /* _ANIMAL_H_ */
/*
* =============================================================================
*
* Filename: animal-base.c
*
* Description: animal base class.
*
* =============================================================================
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h> #include "animal-base.h" /* 基类的构造函数,需要显示调用 */
animal_t * animal_init(char *name)
{
assert(name != NULL);
size_t name_len = strlen(name); animal_t *animal = (animal_t *)malloc(sizeof(animal_t)
+ sizeof(animal_ops_t) + name_len + 1);
memset(animal, 0, (sizeof(animal_t) + sizeof(animal_ops_t)
+ name_len + 1));
animal->name = (char *)animal + sizeof(animal_t);
memcpy(animal, name, name_len);
animal->animal_ops = (animal_ops_t *)((char *)animal
+ sizeof(animal_t) + name_len + 1); return animal;
} /* 基类的有关操作,如吃,走,说等等 */
void animal_eat(animal_t *animal, char *food)
{
animal->animal_ops->eat(food);
return;
} void animal_walk(animal_t *animal, int steps)
{
animal->animal_ops->walk(steps);
return;
} void animal_talk(animal_t *animal, char *msg)
{
animal->animal_ops->talk(msg);
return;
} /* 基类的析构函数,需要显示调用 */
void animal_die(animal_t *animal)
{
assert(animal != NULL); free(animal);
return;
}

汪星人 dog 类的实现代码:

#include "animal-base.h"

typedef struct dog_s_ dog_t;

struct dog_s_ {
animal_t base; /* 继承自 animal 基类 */ /* 以下还可以添加与 dog 相关的属性和方法(函数指针), 如: */
/* char *owner; // dog 的主人 */
/* void (*hunt)(const char *rabbit); // 猎兔犬 */
}; extern dog_t * dog_init();
extern void dog_die(dog_t * dog);
/*
* =============================================================================
*
* Filename: dog.c
*
* Description: dog class derived from animal base class.
*
* =============================================================================
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #include "dog.h" static void eat(char *food); static void walk(int steps); static void talk(char *msg); dog_t * dog_init()
{
dog_t *dog = (dog_t *)malloc(sizeof(dog_t));
animal_t *animal = (animal_t *)animal_init("doggggggggggggg");
memcpy(&(dog->base), animal, sizeof(animal_t)); dog->base.animal_ops->eat = eat;
dog->base.animal_ops->walk = walk;
dog->base.animal_ops->talk = talk; free(animal);
return dog;
} void dog_die(dog_t *dog)
{
/* nothing to do here. */
} static void eat(char *food)
{
printf("I'm a dog, I eat %s\n", food);
} static void walk(int steps)
{
printf("I'm a dog, I can jump %d steps one time\n", steps);
} static void talk(char *msg)
{
printf("I'm a dog, I talk my language %s\n", msg);
}

喵星人(cat 类) 的实现代码:

/*
* =============================================================================
*
* Filename: cat.h
*
* Description: cat class derived from animal base class.
*
* =============================================================================
*/
#include "animal-base.h" typedef struct cat_s_ cat_t; struct cat_s_ {
animal_t base; /* 继承自 animal 基类 */ /* 以下还可以添加与 cat 相关的属性和方法(函数指针), 如: */
/* char *owner; // cat 的主人 */
/* void (*hunt)(const char *rabbit); // 猎兔犬 */
}; extern cat_t * cat_init();
extern void cat_die(cat_t * cat);
/*
* =============================================================================
*
* Filename: cat.c
*
* Description: cat class derived from animal base class.
* =============================================================================
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #include "cat.h" static void eat(char *food); static void walk(int steps); static void talk(char *msg); cat_t * cat_init()
{
cat_t *cat = (cat_t *)malloc(sizeof(cat_t));
animal_t *animal = (animal_t *)animal_init("cat");
memcpy(&(cat->base), animal, sizeof(animal_t)); cat->base.animal_ops->eat = eat;
cat->base.animal_ops->walk = walk;
cat->base.animal_ops->talk = talk; free(animal);
return cat;
} void cat_die(cat_t *cat)
{
/* nothing to do here. */
} static void eat(char *food)
{
printf("I'm a cat, I eat %s\n", food);
} static void walk(int steps)
{
printf("I'm a cat, I can jump %d steps one time\n", steps);
} static void talk(char *msg)
{
printf("I'm a cat, I talk my language %s\n", msg);
}

最后,测试代码如下:

/*
* =============================================================================
*
* Filename: main.c
*
* Description: main test.
*
*
* =============================================================================
*/
#include <stdio.h> #include "animal-base.h"
#include "dog.h"
#include "cat.h" int main(int argc, const char *argv[])
{
dog_t *dog = dog_init();
cat_t *cat = cat_init(); /* dog 类测试 */
animal_eat(dog, "bones");
animal_walk(dog, 5);
animal_talk(dog, "wuang wuang wuang..."); /* cat 类测试 */
animal_eat(cat, "fish");
animal_walk(cat, 3);
animal_talk(cat, "miao miao miao..."); }

还有Makefile :

all:main

main:main.o dog.o cat.o animal-base.o
gcc -o $@ $^ main.o:main.c cat.o:cat.c dog.o:dog.c animal-base.o:animal-base.c .PHONY:clean clean:
rm main main.o dog.o cat.o animal-base.o

最后执行结果为:

I'm a dog, I eat bones
I'm a dog, I can jump 5 steps one time
I'm a dog, I talk my language wuang wuang wuang...
I'm a cat, I eat fish
I'm a cat, I can jump 3 steps one time
I'm a cat, I talk my language miao miao miao...

c语言中继承和多态的简单实现的更多相关文章

  1. Golang 中的 面向对象: 方法, 类, 方法继承, 接口, 多态的简单描述与实现

    前言: Golang 相似与C语言, 基础语法与C基本一致,除了广受争议的 左花括号 必须与代码同行的问题, 别的基本差不多; 学会了C, 基本上万变不离其宗, 现在的高级语言身上都能看到C的影子; ...

  2. [转]Java中继承、多态、重载和重写介绍

    什么是多态?它的实现机制是什么呢?重载和重写的区别在那里?这就是这一次我们要回顾的四个十分重要的概念:继承.多态.重载和重写. 继承(inheritance) 简单的说,继承就是在一个现有类型的基础上 ...

  3. python中继承和多态

    继承和多态 继承 引入继承 我们有这样一个需求 模仿英雄联盟定义两个英雄类 1.英雄要有昵称.攻击力.生命值属性 2.实例化出两个英雄对象 3.英雄之间可以互殴,被殴打的一方掉血,血量小于0则判断为死 ...

  4. c++的类的封装/继承/多态的简单介绍

    本篇文章仅仅从很表层来介绍一个C++语言中的类,包括什么是类,类的封装性/继承性和多态性.高手直接跳过吧,看了浪费时间,新手或者想温习一下的可以浏览看看. 1. 什么是类? 到底什么是类(class) ...

  5. JavaSE学习总结(五)——封装,继承,多态很简单

    java面向对象的三大特性是:封装.继承与多态,是面向对象编程的核心. 一.封装 简单说封装就是将同一类事物的特性与功能包装在一起,对外暴露调用的接口. 封装:封装也称信息隐藏,是指利用抽象数据类型把 ...

  6. C#中继承和多态

    1.继承的概念 继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用已存在的类的功能. 为了提高软件模块的可复用性和可扩充性,以便提高软件的开发效率,我们总 ...

  7. iOS开发-OC语言 (七)继承、多态、类别

    继承.多态.类别 学习目标 1.继承的含义 2.父类子类的别称 3.字段和消息的继承 4.重写和重写消息的调用 5.多态 6.类别(Category) ======================== ...

  8. 第一单元总结:基于基础语言、继承和接口的简单OOP

    前情提要 到目前为止,OO课程已经完成了前三次的作业,分别为: 第一次作业:简单多项式的构造和求导.[正则表达式][数据结构][排序] 第二次作业:含三角函数因子的复杂多项式的构造.求导和化简.[递归 ...

  9. C#——面对对象之封装、继承、多态的简单理解

    一.封装 隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读取和修改的访问级别. 简单来多,就是讲我们所需要的代码打包封装进入一个类里面,便于我们调用,操作.这就是封装. 这样就隔离了具体 ...

随机推荐

  1. HDOJ-ACM1018(JAVA)

    题意: 求n!的位数,0<n<10^7 思路:log10(1)+log10(2)+···+log10(n) = log10(n!)   [题目的考点就在这吧] 解题: import jav ...

  2. Stack Overflow 上人气最旺的 10 个 Java 问题

    1. 为什么两个(1927年)时间相减得到一个奇怪的结果? (3623个赞) 如果执行下面的程序,程序解析两个间隔1秒的日期字符串并比较: public static void main(String ...

  3. eclipse安装插件checkstyle

    最近听说了一个eclipse神器:checkstyle,可以帮助java开发人员规范代码,对我这种有代码洁癖的人来说,这有着不小的魔力啊,必然要安装试一试啊. 我最喜欢的安装方式是 输入一个安装网址, ...

  4. 一步一步学android控件(之十六)—— CheckBox

    根据使用场景不同,有时候使用系统默认的CheckBox样式就可以了,但是有时候就需要自定义CheckBox的样式.今天主要学习如何自定义CheckBox样式.在CheckBox状态改变时有时需要做一些 ...

  5. Ubuntu 12.04 安装搜狗输入法

    安装指南 Ubuntu / Ubuntu Kylin 14.04 LTS 版本 只需双击下载的 deb 软件包,即可直接安装搜狗输入法. Ubuntu 12.04 LTS 版本 由于 Ubuntu 1 ...

  6. Android实时监听网络状态(1)

    其实手机在网络方面的的监听也比较重要,有时候我们必须实时监控这个程序的实时网络状态,android在网络断开与连接的时候都会发出广播,我们通过接收系统的广播就可以实现网络的监听. 1.添加访问网络和获 ...

  7. Java凝视Override、Deprecated、SuppressWarnings具体解释

    一.什么是凝视     说起凝视,得先提一提什么是元数据(metadata).所谓元数据就是数据的数据.也就是说,元数据是描写叙述数据的.就象数据表中的字段一样,每一个字段描写叙述了这个字段下的数据的 ...

  8. paip. mysql如何临时 暂时 禁用 关闭 触发器

    paip. mysql如何临时 暂时 禁用 关闭 触发器 作者Attilax ,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http://blog.csdn ...

  9. js 获取浏览器版本号

    1.在web开发中,会常常让你推断当前使用的是那个浏览器及浏览器的那个版本号,依据浏览器版本号来调整CSS的样式, 使在web界面在各个浏览器展现达到最佳的效果,以下是获取当前浏览器的代码: getB ...

  10. android112 jni 把java的字符串转换成c的字符串,数组处理

    package com.itheima.charencode; import android.os.Bundle; import android.app.Activity; import androi ...