纯c语言实现面向对象分析与示例分享

C语言的对象化模型
面向对象的特征主要包括:
.封装,隐藏内部实现
.继承,复用现有代码
.多态,改写对象行为
1.1  封装
封装是一种信息隐蔽技术,它体现于类的说明,是对象的重要特性。封装使数据和加工该数据的方法(函数)封装为一个整体,以实现独立性很强的模块,使得用户只能见到对象的外特性(对象能接受哪些消息,具有那些处理能力),而对象的内特性(保存内部状态的私有数据和实现加工能力的算法)对用户是隐蔽的。封装的目的在于把对象的设计者和对象者的使用分开,使用者不必知晓行为实现的细节,只须用设计者提供的消息来访问该对象。
在C语言中,大多数函数的命名方式是动词+名词的形式,例如要获取一个semaphore,会命名
成take_semaphore,重点在take这个动作上。面向对象编程中刚好相反,命名为rt_sem_take,即名词+动词的形式,重点在名词上,体现了一个对象的方法。另外对于某些方法,仅局限在对象内部使用,它们将采用static修辞把作用范围局限在一个文件的内部。通过这样的方式,把一些不想让用户知道的信息屏蔽在封装里,用户只看到了外层的接口,从而形成了面向对象中的最基本的对象封装实现。

一般属于某个类的对象会有一个统一的创建,析构过程。
对象内存数据块已经存在,需要对它进行初始化 – rt_sem_init;对象内存数据块还未分配,需要创建并初始化 – rt_sem_create。可以这么认为,对象的创建(create)是以对象的初始化(init)为基础的,创建动作相比较而言多了个内存分配的动作。
相对应的两类析构方式:
.由rt_sem_init初始化的semaphore对象 – rt_sem_detach;
.由rt_sem_create创建的semaphore对象 – rt_sem_delete.

1.2  继承
继承性是子类自动共享父类之间数据和方法的机制。它由类的派生功能体现。一个类直接继承其它类的全部描述,同时可修改和扩充。继承具有传递性。继承分为单继承(一个子类只有一父类)和多重继承(一个类有多个父类,当前RT-Thread的对象系统不能支持)。类的对象是各自封闭的,如果没继承性机制,则类对象中数据、方法就会出现大量重复。继承不仅支持系统的可重用性,而且还促进系统的可扩充性。

类似的实现代码如下程序清单:


代码如下:

/*  父类  */
struct  parent_class
{
  int  a,  b;
  char  *str;
};

/*  继承于父类的子类  */
struct  child_class
{
  struct  parent class  p;
  int  a,  b;
};

/*  操作示例函数*/
void  func()
{
  struct  child_class  obj,  *obj_ptr;  /*  子类对象及指针  */
  struct  parent_class  *parent_ptr;  /*  父类指针  */
  obj_ptr  =  &obj;

/*  取父指针  */
  parent_ptr  =  (struct  parent*)  &obj;

/*  可通过转换过类型的父类指针访问相应的属性  */
  parent ptr->a  =  1;
  parent ptr->b  =  5;

/*  子类属性的操作  */
  obj ptr->a  =  10;
  obj ptr->b  =  100;
}

在上面代码中,注意child_class结构中第一个成员p,这种声明方式代表child_class类型的数据中开始的位置包含一个parent_class类型的变量。在函数func中obj是一个child_class对象,正像这个结构类型指示的,它前面的数据应该包含一个parent_class类型的数据。在第21行的强制类型赋值中parent_ptr指向了obj变量的首地址,也就是obj变量中的p对象。好了,现在parent_ptr指向的是
一个真真实实的parent类型的结构,那么可以按照parent的方式访问其中的成员,当然也包括可以使用和parent结构相关的函数来处理内部数据,因为一个正常的,正确的代码,它是不会越界访问parent结构体以外的数据。经过这基本的结构体层层相套包含,对象简单的继存关系就体现出来了:父对象放于数据块的最前方,代码中可以通过强制类型转换获得父对象指针。

1.3  多态
对象根据所接收的消息而做出动作。同一消息为不同的对象接受时可产生完全不同的行动,这种现象称为多态性。利用多态性用户可发送一个通用的信息,而将所有的实现细节都留给接受消息的对象自行决定,如是,同一消息即可调用不同的方法。例如:抽象设备具备接口统一的读写接口。串口是设备的一种,也应支持设备的读写。但串口的读写操作是串口所特有的,不应和其他设备
操作完全相同,例如操作串口的操作不应应用于SD卡设备中。多态性的实现受到继承性的支持,利用类继承的层次关系,把具有通用功能的协议存放在类层次中尽可能高的地方,而将实现这一功能的不同方法置于较低层次,这样,在这些低层次上生成的对象就能给通用消息以不同的响应。

对象模型采用结构封装中使用指针的形式达到面向对象中多态的效果,例如:


代码如下:

/*  抽象父类  */
struct  parent_class
{
  int  a;

/*  反映不同类别属性的方法  */
  void  (*vfunc)(int  a);
}

/*  抽象类的方法调用  */
void  parent_class_vfunc(struct  parent_class  *self,  int  a)
{
  assert(self  !=  NULL);
  assert(slef->vfunc  !=  NULL);

/*  调用对象本身的虚拟函数  */
  self->vfunc(a);
}

/*  继承自parent class的子类  */
struct  child_class
{
  struct  parent_class  parent;
  int  b;
};

/*  子类的构造函数  */
void  child_class_init(struct  child_class*  self)
{
  struct  parent_class*  parent;

/*  强制类型转换获得父类指针  */
  parent  =  (struct  base_class*)  self;
  assert(parent  !=  NULL);

/*  设置子类的虚拟函数  */
  parent->vfunc  =  child_class_vfunc;
}

/*  子类的虚拟函数实现  */
static  void   child class vfunc(struct  child class*self,  int  a)
{
  self->b  =  a  +  10;
}

代码如下:

#include <stdio.h>
#include <stdlib.h>

//接口
#ifndef Interface
#define Interface struct
#endif

//类
#ifndef Class
#define Class struct
#endif

//抽象形状类
Class Shape;
typedef Class Shape shape;
//抽象形状类的方法声明
shape* Shape(int edges);
int shape_getEdges(shape *);
int shape_getArea(void);
void _Shape(shape *);

//三角形类
Class Triangle;
typedef Class Triangle triangle;
//三角形类的方法声明
triangle * Triangle(int bottom, int height);
int triangle_getEdges(triangle *);
int triangle_getArea(triangle *);
void _Triangle(triangle *);

//矩形类
Class Rectangle;
typedef Class Rectangle rectangle;
//矩形类的方法声明
rectangle * Rectangle(int bottom, int height);
int rectangle_getEdges(rectangle *);
int rectangle_getArea(rectangle *);
void _Rectangle(rectangle *);

//抽象形状类实现
Class Shape
{
    int edges;
    int (*getEdges)(shape*);
    int (*getArea)(void);
};

//形状类构造函数
shape* Shape(int edges)
{
    shape * obj = (shape *) malloc(sizeof(shape));
    obj->edges = edges;
    obj->getEdges = shape_getEdges;
    obj->getArea = shape_getArea;
    return obj;
}

int shape_getEdges(shape* obj)
{
    return obj->edges;
}

int shape_getArea(void)
{
    return -1;
}

//形状类析构函数
void _Shape(shape * obj)
{
    if(obj == NULL)
        return;
    free(obj);
}

//三角形类实现
Class Triangle
{
    shape * super;
    int bottom;
    int height;
    int (*getEdges)(triangle *);
    int (*getArea)(triangle *);
};

//三角形类构造函数
triangle * Triangle(int bottom, int height)
{
    triangle* obj = (triangle*) malloc(sizeof(triangle));
    //调用Shape构造函数用于实现继承
    obj->super = Shape(3);
    obj->bottom = bottom;
    obj->height = height;
    obj->getEdges = triangle_getEdges;
    obj->getArea = triangle_getArea;
    return obj;
}

int triangle_getEdges(triangle * obj)
{
    return obj->super->edges;
}

int triangle_getArea(triangle * obj)
{
    return (obj->bottom * obj->height) / 2;
}

//三角形类析构函数
void _Triangle(triangle * triangle)
{
    _Shape(triangle->super);

if(triangle == NULL)
    {
        return;
    }

free(triangle);
}

//矩形类实现
Class Rectangle
{
    shape * super;
    int bottom;
    int height;
    int (*getEdges)(rectangle *);
    int (*getArea)(rectangle *);
};

//矩形类构造函数
rectangle * Rectangle(int bottom, int height)
{
    rectangle * obj = (rectangle *)malloc(sizeof(rectangle));
    //调用Shape构造函数用于实现继承
    obj->super = Shape(4);
    obj->bottom = bottom;
    obj->height = height;
    obj->getEdges = rectangle_getEdges;
    obj->getArea = rectangle_getArea;
    return obj;
}

int rectangle_getEdges(rectangle * obj)
{
    return obj->super->edges;
}

int rectangle_getArea(rectangle * obj)
{
    return (obj->bottom * obj->height);
}

//矩形类析构函数
void _Rectangle(rectangle * obj)
{
    _Shape(obj->super);
    if(obj == NULL)
    {
        return;
    }
    free(obj);
}

//测试
void main(){
    shape* shapeObj = Shape(0);
     printf("%d\n", shapeObj->getEdges(shapeObj));
    printf("%d\n", shapeObj->getArea());
    _Shape(shapeObj);

triangle* triangleObj = Triangle(4, 5);
    printf("%d\n", triangleObj->getEdges(triangleObj));
    printf("%d\n", triangleObj->getArea(triangleObj));
    _Triangle(triangleObj);

rectangle* rectangleObj = Rectangle(4, 5);
    printf("%d\n", rectangleObj->getEdges(rectangleObj));
    printf("%d\n", rectangleObj->getArea(rectangleObj));
    _Rectangle(rectangleObj);
}

(0)

相关推荐

  • c语言实现单链表算法示例分享

    复制代码 代码如下: #include <stdio.h>#include <stdlib.h>typedef char DataType;typedef struct Node{    DataType data;    struct Node * Next;}ListNode,* LinkList;void Judement(LinkList head){ //判断分配内存    if (!head){        printf("Overflow.");

  • c语言文件读写示例(c语言文件操作)

    方法: 复制代码 代码如下: long filesize(char* filename);char* file_get_contents(char* filename);void file_put_contents(char* filename, char* data); 示例: 复制代码 代码如下: #include <stdio.h>#include <stdlib.h>#include <string.h>long filesize(char* filename)

  • linux安装mysql和使用c语言操作数据库的方法 c语言连接mysql

    1. MySQL的安装与配置: 在Ubuntu下安装MySQL方法很简单,使用如下命令: 复制代码 代码如下: sudo apt-get install mysql-server 安装的过程中系统会提示设置root密码,此过程可以跳过,但是建议在安装时提示设置root密码的时候自行设置,免得后面设置麻烦.安装结束之后,系统会启动mysql服务,可以使用命令去查看来验证mysql服务是否已经安装成功: 复制代码 代码如下: ps -el | grep mysql 如果mysql服务没有正常的运行,

  • linux使用gcc编译c语言共享库步骤

    对任何程序员来说库都是必不可少的.所谓的库是指已经编译好的供你使用的代码.它们常常提供一些通用功能,例如链表和二叉树可以用来保存任何数据,或者是一个特定的功能例如一个数据库服务器的接口,就像MySQL. 大部分大型的软件项目都会包含若干组件,其中一些你发现可以用在其他项目中,又或者你仅仅出于组织目的将不同组件分离出来.当你有一套可复用的并且逻辑清晰的函数时,将其构建为一个库会十分有用,这样你就不将这些源代码拷贝到你的源代码中,而且每次都要再次编译它们.除此之外,你还可以保证你的程序各模块隔离,这

  • c语言strftime时间格式化示例

    函数原型: 复制代码 代码如下: size_t strftime (char* ptr, size_t maxsize, const char* format,const struct tm* timeptr ); 代码示例: 复制代码 代码如下: #include <stdio.h>#include <time.h> int main (){    time_t rawtime;    struct tm * timeinfo;    char buffer [128]; tim

  • c语言快速排序算法示例代码分享

    步骤为:1.从数列中挑出一个元素,称为 "基准"(pivot);2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边).在这个分区退出之后,该基准就处于数列的中间位置.这个称为分区(partition)操作.3.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序.递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了.虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iterat

  • c语言实现系统时间校正工具代码分享

    复制代码 代码如下: //*******************************************************************//Time Protocol是一种非常简单的应用层协议.它返回一个未格式化的32位二进制数字, //这个数字描述了从1900年1月1日午夜到现在的秒数.服务器在端口37监听协议请求,以 //TCP/IP或者UDP/IP格式返回响应.将服务器的返回值转化为本地时间是客户端程序的责任. //这里使用的时间服务器是129.132.2.21,更

  • c语言网络编程-标准步骤(改进版)

    server.c 复制代码 代码如下: #include <stdio.h>#include <stdlib.h>#include <string.h>#include <netdb.h>#include <netinet/in.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h> #include <fcntl.h&g

  • c语言多进程tcp服务器示例

    server.h 复制代码 代码如下: #ifndef SERVER_H#define SERVER_H#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <arpa/inet.h>#include <as

  • C语言堆栈入门指南

    C语言堆栈入门指南 在计算机领域,堆栈是一个不容忽视的概念,我们编写的C语言程序基本上都要用到.但对于很多的初学着来说,堆栈是一个很模糊的概念.堆栈:一种数据结构.一个在程序运行时用于存放的地方,这可能是很多初学者的认识,因为我曾经就是这么想的和汇编语言中的堆栈一词混为一谈.我身边的一些编程的朋友以及在网上看帖遇到的朋友中有好多也说不清堆栈,所以我想有必要给大家分享一下我对堆栈的看法,有说的不对的地方请朋友们不吝赐教,这对于大家学习会有很大帮助. 首先在数据结构上要知道堆栈,尽管我们这么称呼它,

  • c语言获取文件大小的示例

    1.fseek 函数原型: 复制代码 代码如下: int fseek ( FILE * stream, long int offset, int origin ); 参数说明:stream,文件流指针:offest,偏移量:orgin,原(始位置.其中orgin的可选值有SEEK_SET(文件开始).SEEK_CUR(文件指针当前位置).SEEK_END(文件结尾). 函数说明:对于二进制模式打开的流,新的流位置是origin + offset. 2.ftell 函数原型:long int ft

  • c语言链表操作示例分享

    复制代码 代码如下: #include <stdio.h>#include <stdlib.h>#include <conio.h>/*以下是为了构建线性链表而定义的结构体*/typedef struct chaink{    char c;    struct chaink * next;    }ck;ck * chain(ck *,int);int print(ck *,int);/*以下是main函数*/int main(void){    printf(&qu

  • c语言网络编程-标准步骤(比较简单)

    c语言网络编程-标准步骤,真的很简单啊 server.c 复制代码 代码如下: #include <stdio.h>#include <stdlib.h>#include <string.h>#include <netdb.h>#include <netinet/in.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h> #d

  • 实现去除c语言注释的小工具

    去除C代码中的注释,1. 单行注释//:2. 多行注释/**/:3. 单行注释以"\"结尾则下一行也为注释:4. 字符串中的注释不处理.说是C语言,但其实所有C语系的都可以,比如Java. 小工具:去除C语言注释  复制代码 代码如下: #include <stdio.h> int main(int argc, char* argv[]) {  enum {    literal,    single,    multiple,    string  } mode = li

  • C语言判断回文数的小例子

    复制代码 代码如下: #include<stdio.h>#include<stdlib.h> int is_palindrome(char* para_str , int len); int main(int argc , char* argv[]){   int n = atol(argv[2]);     if (is_palindrome(argv[1],n))       printf("this string is palindrome !\n"); 

  • c语言实现的hashtable分享

    头文件 hashtable.h 复制代码 代码如下: typedef struct _Bucket{    char *key;    void *value;    struct _Bucket *next;} Bucket; typedef struct _HashTable{    int size;    int total;    struct _Bucket *buckets;} HashTable; int hash_init(HashTable **ht);int hash_fi

  • c语言尾队列tailq使用示例分享

    queue和list的结构定义和操作都在'sys/queue.h'中完成, 主要定义了下面四种数据结构: 1单向列表(single-linked lists)2单向尾队列(single-linked tail queue)3列表(lists)4尾队列(tail queues) 使用示例 复制代码 代码如下: #include <stdio.h>#include <stdlib.h>#include <sys/queue.h> /*  定义一个结构体,它只是尾队列的一个元

  • c语言打开文件函数使用方法

    ANSI C规定文件打开用函数fopen,关闭为fclose. 1.调用方式通常为: 复制代码 代码如下: FILE *fp;fp=fopen(文件名, 打开方式); 2.参数说明: 文件名: 形如"myfile.dat"."F:\data\myfile.dat"等等; 打开方式:"r"(只读) 为输入打开一个文本文件"w"(只写) 为输出打开一个文本文件"a"(追加) 向文件文件尾添加数据"rb

随机推荐