纯C语言实现简单继承机制

0 继承是OO设计的基础

继承是OO设计中的基本部分,也是实现多态的基础,C++,C#,Objective-C,Java,PHP,JavaScript等为OO而设计的语言,其语言本身对实现继承提供了直接支持。而遵循C/Unix设计哲学的语言,从不限定编程风格,而且提供了实现OO的基本支持。下面我们就来看看如何用C语言实现继承。

1 内存布局层面上继承的含义

如今几乎所有程序员都知道继承的抽象含义,对于被用烂了的猫狗继承动物的例子也耳熟能详。在此,我们抛开抽象世界,深入到继承的具体实现上。当然不同的语言对继承的实现机制并不完全相同,但是了解其中一种典型的实现细节对于理解继承是非常有好处的。这里我们以C++为例进行说明。

class B
{
    int x;
    int y;
    int z;
};
class C : B
{
    float f;
    char s[10];
};

上述代码表示子类C继承了父类B,下面是类C的一个实例(对象)的内存布局。

C对象有两部分组成,红色区域是继承自B的部分,蓝色区域是自身特有的。这样一来,红色部分完全可以当成是一个B类对象。

2 利用结构体实现继承的两种方法

2.1 父类对象作为子类的成员

理解了继承的内存布局原理之后,用C来实现继承就非常容易了。最容易想到的方法如下:

struct B
{
    int x;
    int y;
    int z;
};

struct C
{
    struct B objB;
    float f;
    char s[10];
};

上述代码通过在C中包含一个B类型的成员来实现继承,此方法非常直接,但使用起来有一些不太方便。

    struct C objC;
    objC.objB.x = 10;
    ((struct B*)&objC)->x = 10;

要想访问父类的成员x,有两种方法,一种是objC.objB.x;另一种是((struct B*)&objC)->x = 10。这两种方式都看起来不够直接。而在子类方法中访问父类成员是非常频繁的。

void c_member_method(struct C* pObjC)
{
    pObjC->objB.x = 20; /* 访问父类成员 */
    pObjC->f = 0.23f; /* 访问自身成员 */
}

第一种方法,感觉更像是OB风格,而不是OO。

第二种方法,必须进行强制类型转换,感觉语法上不够美观。

2.2 子类包含所有的父类成员

struct C
{
    int x;
    int y;
    int z;

    float f;
    char s[10];
};

把所有的父类成员原样作为子类的成员。这样子类对象访问继承来的成员就非常直接了。

void c_member_method(struct C* pObjC)
{
    pObjC->x = 20; /* 访问父类成员 */
    pObjC->f = 0.23f; /* 访问自身成员 */
}

void main()
{
    struct C objC;
    objC.x = 10;
}

看起来很好,实际上在工程上会存在一个很大的问题:难以维护!例如,每当创建一个子类,必须原样书写所有的父类成员,当父类定义变动时,子类需要做出同样的修改。一旦父类稍具规模,维护这种继承关系将是一场噩梦!

那么如何解决的?

方法是现成的,那就是利用C语言的预处理宏定义#define. 如下所示:

#define B_STRUCT \
    int x;     int y;     int z

struct B
{
    B_STRUCT;
};

struct C
{
    B_STRUCT;
    float f;
    char s[10];
};

当继承层级更深时,例如 C继承B,D继承C,可以照搬此方法。

#define B_STRUCT \
    int x;     int y;     int z

struct B
{
    B_STRUCT;
};

#define C_STRUCT \
    B_STRUCT;     float f;     char s[10]

struct C
{
    C_STRUCT;
};

#define D_STRUCT \
    C_STRUCT;     double d

struct D
{
    D_STRUCT;
};

通过宏定义,可以很容易实现和维护这种继承关系。

3 一点思考

OO思想已经在软件设计上占据了统治地位,直接支持OO的编程语言铺天盖地,但是OO就没有缺陷吗?如何在自己的项目中适量适度使用OO?

时间: 2024-10-13 22:27:27

纯C语言实现简单继承机制的相关文章

纯C语言实现简单封装继承机制

0 继承是OO设计的基础 继承是OO设计中的基本部分,也是实现多态的基础,C++,C#,Objective-C.Java.PHP.JavaScript等为OO而设计的语言,其语言本身对实现继承提供了直接支持.而遵循C/Unix设计哲学的语言,从不限定编程风格.并且提供了实现OO的基本支持.以下我们就来看看怎样用C语言实现继承. 1 内存布局层面上继承的含义 现在差点儿全部程序猿都知道继承的抽象含义,对于被用烂了的猫狗继承动物的样例也耳熟能详.在此,我们抛开抽象世界,深入到继承的详细实现上.当然不

cocos2d JS -> JavaScript 中的简单继承关系

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px "PingFang SC" } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px "PingFang SC"; min-height: 25.0px } span.Apple-tab-span { white-space: pre } JavaScript 语言本身没有提供类,没有其他语言的类继承机制,它的

模块的封装之C语言类的继承和派生

[交流][微知识]模块的封装(二):C语言的继承和派生 在模块的封装(一):C语言的封装中,我们介绍了如何使用C语言的结构体来实现一个类的封装,并通过掩码结构体的方式实 现了类成员的保护.这一部分,我们将 在此的基础上介绍C语言类的继承和派生.其实继承和派生是一个动作的两种不同角度的表达 .当我们继承了一个基类而创造了一个新类时,派生的概念就诞生了.派生当然是从基类派生的.派生出来的类当然是继承了基类的 东西.继承和派生不是一对好基友,他们根本就是一个动作的两种不同的说法,强调动作的起始点的时候

普通青年的状态机,纯C语言

我们第一次接触到状态机,是在数字电路课程里.计数器.串行奇偶检校.检验三个1连续出现的报错电路 等,都需要状态机作为模型.实现这些功能的电路,与状态机的状态转换图.状态转换表都是等价的. 后来,我们再接触状态机,是在编译原理课程里.状态机用于描述与正则表达式匹配的字符串. 再后来,我们在GUI界面设计中,需要设置一些控件在某些条件下 禁用,某些条件下使能,某些条件下打个对号.这也可以用状态机模型来控制. 1. 不要写成 消息响应/事件处理 状态机和消息响应都是 双层 switch-case 结构

javascript 之 prototype继承机制

理解Javascript语言的继承机制 javascript没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instance)的区分,全靠一种很奇特的"原型链"(prototype chain)模式,来实现继承. 1.引言 1994年,网景公司急需一种网页脚本语言,使得浏览器可以与网页互动.工程师Brendan Eich 负责开发这种新语言.他觉得,没必要设计得很复杂,这种语言只要能够完

重温Javascript继承机制

原文:http://mozilla.com.cn/post/21667/ =========================== 上段时间,团队内部有过好几次给力的分享,这里对西风师傅分享的继承机制稍作整理一下,适当加了些口语化的描述,留作备案. 一.讲个故事吧 澄清在先,Java和Javascript是雷锋和雷峰塔的关系.Javascript原名Mocha,当时还叫做LiveScript,创造者是Brendan Eich,现任Mozilla公司首席技术官. 1994年,历史上第一个比较成熟的网

【JavaScript】重温Javascript继承机制

上段时间,团队内部有过好几次给力的分享,这里对西风师傅分享的继承机制稍作整理一下,适当加了些口语化的描述,留作备案. 一.讲个故事吧 澄清在先,Java和Javascript是雷锋和雷峰塔的关系.Javascript原名Mocha,当时还叫做LiveScript,创造者是Brendan Eich,现任Mozilla公司首席技术官. 1994年,历史上第一个比较成熟的网络浏览器——Navigator0.9版诞生在网景公司(Netscape),极为轰动.但是,Navigator0.9只能用来浏览,不

JavaScript大杂烩4 - 理解JavaScript对象的继承机制

面向对象之继承 JavaScript是单根的面向对象语言,它只有单一的根Object,所有的其他对象都是直接或者间接的从Object对象继承(没有指定父类的对象,都被认为是从Object继承的). 在前面我们讨论了面向对象的封装性,在最后的地方也谈到了JavaScript的继承是通过原型和原型链实现的,下面我们就详细的展开这个问题:JavaScript到底是如何实现继承的? 继承的本质 继承的本质是重用,从语法上来讲,继承就是"D是B"的描述,其中B是基类,描述共性,D是子类,描述特性

JavaScript中继承机制的模仿实现

首先,我们用一个经典例子来简单阐述一下ECMAScript中的继承机制. 在几何学上,实质上几何形状只有两种,即椭圆形(是圆形的)和多边形(具有一定数量的边).圆是椭圆的一种,它只有一个焦点.三角形.矩形和五边形都是多边形的一种,具有不同数量的边.正方形是矩形的一种,所有的边等长.这就构成了一种完美的继承关系. 在这个例子中,形状(Shape)是椭圆形(Ellipse)和多边形(Polygon)的基类(base class)(所有类都由它继承而来).椭圆具有一个属性 foci,说明椭圆具有的焦点