一、类的封装实现:借用高焕堂的宏头文件,类很容易封装为如下的格式

1、类的定义,其中 CLASS() 是 lw_oopc_kc.h 中定义的宏

#include "lw_oopc_kc.h"
CLASS(A)
{
int a; void(*init)(void*,int); void(*put)(void*);
};

2、成员函数的实现

类的封装实质是用借用 struct 结构体,用函数指针来表示 C++中类的方法(成员函数)。接下来给类 A 的方法写实体函数。

void init_A(void *t,int x)
{
A *cthis = (A*)t;
cthis->a = x;
}
void put_A(void*t)
{
A *cthis = (A*)t;
printf(" %d ",cthis->a);
}

3、类(结构体)中的函数指针与实现函数的关联 通过下面的宏把类的方法(函数指针)和实现函数关联:

CTOR(A)
FUNCTION_SETTING (init, init_A); FUNCTION_SETTING (put, put_A);
END_CTOR

4、对象的定义、构造和初始化

如果没有这个连接处理,类(实际是 struct)中的函数指针就没有函数的功能。函数 init_A()是 XXX_A() 的命名模式,是指明 XXX_A()属于 A 类的函数,方便程序的理解和维护。下面就是要构造 类。在 C++中这个工作系统自动调用构造函数实现而在 C 中,这个过程智能显示调用来实现。借助 lw_oopc_kc.h (或"lw_oopc.h")可以利用宏CLASS_CTOR(class,obj)来将定义的对象进行构造,使之 有数据的同时有方法的功能。实例化一个对象 3 步子如下:

A   aa1;                           // 1、定义对象
CLASS_CTOR(A,aa1);       // 2、构造对象—使得函数指针和函数关联
aa1.init(&aa1, 10);               // 3、初始化对象的成员变量,注意要: &aa1(取地址)

二、C 继承的实现:

1、子类的定义:在类的开头借用已经定义的类进行定义一个变量,为了更加明白,表明是继承,增加一个宏定义:

CLASS(B)
{
INHERIT(A);              //  继承 A 类 int b;                                   //  子类的成员 void (*init) (void*, int x);
void (*put) (void*);
};

于是以类 B 继承类 A 为例子如下:

void init_B (void*t, int x, int y)
{
B *cthis =   (B*) t;
CLASS_CTOR(A, cthis->A);               //----继承的基类在这里构造,对象是 cthis->A cthis->A.init(&cthis->A, x);//----继承的基类的初始化, 注意:&cthis->A cthis->b = y;
}
void put_B (void *t)
{
B *cthis = (B*) t;
cthis->A.put (&cthis->A);                    //---子类调用父类的方式
printf(" %d ",cthis->b);                          //---输出类成员值
}

2、子类的成员函数实现,为了方便辨别,类 B 的成员函数带后缀 ‘_B’

int main()
{
A aa1; B b;
CLASS_CTOR(A,aa1);                              //--构造 aa1 对象 aa1.init(&aa1,5);     //--初始化 aa1 对象aa1.put(&aa1);            //--调用 aa1 对象的成员函数
CLASS_CTOR(B, b);                                //---构造 b 对象
b.init(&b,100,78);                                     //--初始化 b 对象,包括基类 A 的构造和初始化
b.put(&b);                                                //--调用 b 对象成员函数
b.A.put(&b.A);                                         //--调用 b 对象的基类成员函数
return 0;
}

3、子类的构造函数,和无继承类一样,将函数指针和函数关联

CTOR(B)

  FUNCTION_SETTING (init, init_B); //---函数指针和函数关联的宏

  FUNCTION_SETTING (put, put_B); END_CTOR

说明:对基类的构造,不能在子类的构造宏 CTOR(B) 和 END_CTOR 之间进行,因为那时候子类 B 没有实例化,故没有实体对象,CLASS_CTOR(A, cthis->A);不能放在里面,只好放在 init_B() 函数里面,因为那时候 B 类已经有实例化对象了。这样的做法与 C++的做法不一样。C++在构造 B 的对象时,先调用 A 类的构造函数实例化对象中的基类部分。下面为main()函数的调用处理:

int main()
{
A aa1; B b;
CLASS_CTOR(A,aa1);                              //--构造 aa1 对象 aa1.init(&aa1,5);    //--初始化 aa1 对象aa1.put(&aa1);                //--调用 aa1 对象的成员函数
CLASS_CTOR(B, b);                                //---构造 b 对象
b.init(&b,100,78);                                     //--初始化 b 对象,包括基类 A 的构造和初始化
b.put(&b);                                                //--调用 b 对象成员函数
b.A.put(&b.A);                                         //--调用 b 对象的基类成员函数
return 0;
}

输出结果为:5 100 78 100

三、多态的实现:

多态,简而言之即一个接口,多种实现。也就是用相同的抽象类的代码实现不同 的功能。在 C 中多态的实现是通过接口来实现的。借用 lw_oopc.h 宏文件,设计一个计算的多态例子如下:

1、接口的定义:本例是实现加法、减法运算。

加和减都是调用类的同一个成员函数,却分别实现 了加、减的功能。本例的接口表示获得计算结果,但不知道采样什么样的计算方法。

/*    operater.h   */
#ifndef OPER_H
#define OPER_H INTERFACE(IOPERATOR)
{
double (*GetResult)(double,double);
};
#endif
/*-------------end of operater.h ------------------*/

2、 在加法类 Add 中实现接口 IOPERATOR

/*****   Add.C ***/
#include "lw_oopc_kc.h"
#include"operater.h"      // 头文件顺序很重要,lw_oopc_kc.h 在前,原因很简单不解释
#include "classes.h"
/************************** 类 Add 定义在 classes.h 中
CLASS(Add)
{
IMPLEMENTS(IOPERATOR);
};************/
static double GetResult(double a,double b)
{
return (a+b);
}
CTOR(Add)
FUNCTION_SETTING(IOPERATOR.GetResult,GetResult); END_CTOR
/***----- END OF ADD.C-----****/

3、 在减法类 Sub 中实现接口 IOPERATOR

/***--- Sub.c ---******/
#include "lw_oopc_kc.h"
#include"operater.h"
#include "classes.h"
/***********类 Sub 定义在 classes.h 中
CLASS(Sub)
{
IMPLEMENTS(IOPERATOR);
};*/
static double GetResult(double a,double b)
{
return (a-b);
}
CTOR(Sub) FUNCTION_SETTING(IOPERATOR.GetResult,GetResult);
END_CTOR
/***----- END OF Sub.C-----****/

4、 组合,把 operater.h、Add.C、Sub.C 和 main.C 组成一个工程,main.c 文件如下:

/***--- main.c ---******/
#include<stdio.h>
#include "lw_oopc_kc.h"
#include"operater.h"      // 头文件顺序很讲究,lw_oopc_kc.h 必须在前面
#include "classes.h" int  main()
{
int a = 10, b=5;
int c1,c2;
IOPERATOR *poper;               //--定义接口指针,用指针实现多态
Add A;                          //---对象 A 成员函数实现加法
Sub S;                          //---对象 B 成员函数实现减法
CLASS_CTOR(Add, A); CLASS_CTOR(Sub, S);
//---静态内存处理方法
poper = &A;        //也可以动态内存方法:oper = New(Add); 记得 free()
c1 = (poper->GetResult(a,b));      // c1 的结果 = 15 ( a+b)
poper = &S;
c2 = poper->GetResult(a,b);      // c2 结果= 5 (a-b)
return 0;
}
/***----- END OF main.C-----****/

总结:

1、在 lw_oopc_kc.h 的基础上,为了增加可理解性,不改变原作含义为前提下,增加了以下宏

#define CLASS_CTOR(Class,obj)       Class##Setting(&obj)        //--对象的构造宏
#define INHERIT(BASE)     IMPLEMENTS(BASE)                        //---类继承宏
#ifndef LW_OOPC_PURE_STATIC
#ifndef LW_OOPC_STATIC
#define New(Class)     Class##New()                  //--对象动态构造宏
#endif
#endif

2、类的实例化必须有 3 步:

定义、构造、初始化。尤其初始化时候通常是通过指针的应用来实现对类内部成员的访问。

3、继承实现方法:

用父类名在子类中定义一个对象作为子类的一个成员变量,通过拥有该对象实 现子类对父类功能的拥有,即继承。

4、注意:子类成员中用父类定义的对象,其构造函数要放在子类的初始化函数里(本人的解决方 法),因为子类的构造函数通过宏实现,不能直接调用父类的构造函数(如果您有更好办法,请和给大家分享)。

5、 函数和函数指针的写法:将函数名变为指针,函数参数只要参数说明。

e.g. double GetResult(double a,double b) 转为函数指针为:

附:lw_oopc_kc.h 宏文件内容

/*  lw_oopc_kc.h */
#ifndef _LW_OOPC_H
#define _LW_OOPC_H
#include <stdlib.h>
#define CLASS(type) \ typedef struct type type; \ struct type
#ifndef LW_OOPC_PURE_STATIC
#ifndef LW_OOPC_STATIC
#ifndef LW_OOPC_DYNAMIC
#define CTOR(type) \
void* type##Setting(type*);      \
void* type##New()\
{  \
struct type *t; \
t = (struct type *)malloc(sizeof(struct type)); \
return type##Setting(t); \
}  \
void* type##Setting(type *t) \
{
#else
#define CTOR(type) \
void* type##New()\
{  \
struct type *t; \
t = (struct type *)malloc(sizeof(struct type));
#endif
#else
#define CTOR(type) \
void* type##Setting(type *t) \
{
#endif
#endif
#define END_CTOR return (void*)t;      }
#define FUNCTION_SETTING(f1, f2)      t->f1 = f2;
#define IMPLEMENTS(type) type type
#define INTERFACE(type) \ typedef struct type type; \ struct type
#endif
/*     end     */

用 C 语言实现面向对象编程相关推荐

  1. C++学习笔记:(七)C语言实现面向对象编程

    面试官:C和C++有什么不同? 应聘者:一个是面向过程,一个是面向对象. 这样的答案在我看是不完全正确,因为面向过程编程和面向对象编程是编程思想,C++可以用面向过程的思想编程,同样,C语言也可以用面 ...

  2. C 语言实现面向对象编程

    C 语言实现面向对象编程 1.引言 面向对象编程(OOP)并不是一种特定的语言或者工具,它只是一种设计方法.设计思想.它表现出来的三个最基本的特性就是封装.继承与多态.很多面向对象的编程语言已经包含这 ...

  3. 一步步分析-C语言如何面向对象编程

    这是道哥的第009篇原创 一.前言 在嵌入式开发中,C/C++语言是使用最普及的,在C++11版本之前,它们的语法是比较相似的,只不过C++提供了面向对象的编程方式. 虽然C++语言是从C语言发展而来 ...

  4. ctor c语言,一步步分析-C语言如何面向对象编程

    这是道哥的第009篇原创 一.前言 在嵌入式开发中,C/C++语言是使用最普及的,在C++11版本之前,它们的语法是比较相似的,只不过C++提供了面向对象的编程方式. 虽然C++语言是从C语言发展而来 ...

  5. c语言实现面向对象编程

    文章目录 概述 框架介绍 基类 c++基类 c 实现基类 派生类 c++派生类 C实现派生类 基于模型的多重继承 C++的多重继承 c的多重继承 对象创建和使用 C++ 应用 C应用 概述   有一种 ...

  6. 老汤回味——C语言与面向对象编程

    今天的文章我们来看看如何结合面向对象的思想使用C语言写出结构良好的代码.直接看代码,然后我们来分析一下代码中的含义.首先是头文件user.h: #ifndef USER_H #define USER_ ...

  7. Java语言基础-面向对象编程三步走之打开冰箱门

    开头: 何谓"面向对象" 面向对象是一种编程思想. 思想是一个很虚无缥缈的东西,但是它可以从一个人的具体行动中体现出来,如果说你坚持每天跑步,每天读书,做一些有益于身心健康的事情, ...

  8. PHP语言之面向对象编程

    第3关:面向对象编程与数据库综合运用 <?php class model {protected $db; //数据库操作类实例protected $tableName; //待操作的表名prot ...

  9. java语言基础-面向对象编程-方法(廖雪峰老师官网学习记录)

    Java是一种面向对象的编程语言. 面向对象编程,英文是Object-Oriented Programming,简称OOP. 面向对象编程,是一种通过对象的方式,把现实世界映射到计算机模型的一种编程方 ...

  10. C语言中面向对象编程

    C语言中面相对象的编程 面向对象的重要思想就是数据隐藏,在面向对象语言中,对象可以包含私有变量.这样我们可以说他们具有内部状态,这些内部状态对其他对象是透明的.全局变量可以通过设置变量作用域来模拟私有 ...

最新文章

  1. 再学 GDI+[25]: TGPPen - 宽度、颜色与线帽
  2. web.py mysql_用Web.py 连接 MySQL 的时候怎么样连接远程数据库
  3. 使用java理解程序逻辑 第十二章_Java弱引用的理解与使用
  4. gitlab-ci详细说明
  5. 关于WinCE6.0补丁包的一点说明
  6. Surface Pro电磁笔故障
  7. 【论文】Realtime lane tracking of curved local road 检测和跟踪功能
  8. 超定方程组 matlab
  9. 11种基于ARM的嵌入式操作系统
  10. 免费专业的linux web应用防火墙国内排名推荐
  11. 智能优化算法:饥饿游戏搜索算法-附代码
  12. win10 网络重置后WIFI不见了
  13. 运用京东云代码托管、云编译、云部署等产品进行蓝绿部署简单实践
  14. ES match query
  15. QML---Repeater
  16. 学习英文之社区,博客及源码
  17. UML正日薄西山的13个理由
  18. 论文阅读——Image Inpainting for Irregular Holes Using Partial Convolutions
  19. Hot Door CADtools13 for Illustrator 2019-2022
  20. 2009春运,广州是最具人文关怀的城市

热门文章

  1. 【Java 虚拟机原理】Class 字节码二进制文件分析 三 ( 访问和修饰标志 | 类索引 | 父类索引 | 接口计数器 | 接口表 | 字段计数器 | 字段表 )
  2. 【Android 进程保活】Android 进程优先级 ( 前台进程 | 可见进程 | 服务进程 | 后台进程 | 空进程 )
  3. Windows 8各个版本的功能详解与对比【中文详表】
  4. linux -- ./configure --prefix 命令
  5. 数据库复习总结(12)数据检索
  6. 利用php比较精确的统计在线人数的办法
  7. Mysql数据库主从及主主复制配置演示
  8. vs2012 发布网站时出现 sgen.exe 已退出 代码为 1
  9. 加解压开源组件-SharpZipLib
  10. 32位处理器的寄存器介绍