用C实现面向对象

C语言实现面向对象之继承性 面向对象有三个最为明显的特性:继承、封装、多态性。C++、java、C#等面向对象语言在语言层次上支持OOP,而OOP本身其实并不是专门为语言设计的。虽然C语言在语言层次上不支持面向对象,但是通过C语言也是可以实现OOP的特性的。 下面就主要讲述通过C语言实现面向对象的三大特性之一:继承性。 “继承”是面向对象中的一个概念,如果一个类A继承自另一个类B,就把这个类A称之为类B的子类,而B类则是 阅读详情

    很多开发工程师都是从学习C语言的"Hello world!"开始的,都知道C语言中的指针是一把利剑,一不留意就伤了自个。但其C语言绝对是一个宗师级语言,这是不可否认的。
    由于我们开发的需要在多个平台上运行且需要面向对象的一些特性、所以特写此文章。权当抛砖引玉。
    
一、概述
     C语言是一种面向过程的程序设计语言、而C++在语言级别上添加了很多新机制(继承,多态等)
     因此这里说说使用C语言实现封装,继承和多态的方法。


二、基本知识


1、结构体


在C语言中,常把一个对象用结构体进行封装,这样便于对对象进行操作,比如:1
  strcut Point{
int x;
int y;
};




结构体可以嵌套。因而可以把一个结构体当成另一个结构体的成员:
  struct Circle { 
struct Point point_;
int radius;
};




该结构体与以下定义完全一样(包括内存布置都一样):
struct Circle { 
int x; 
int y; 
int radius; 
};




2、函数指针


函数指针是指针的一种,它指向函数的首地址(函数的函数名即为函数的首地址),可以通过函数指针来调用函数。


如函数:


int func(int a[], int n);


可以这样声明函数指针:


int (*pFunc)(int a[], int n);


这样使用:


pFunc = func;


(*pFunc)(a, n);【或者PFunc(a, n)】


可以用typedef定义一个函数指针类型,如:


typdef int (*FUNC)(int a[], int n)


可以这样使用:


int cal_a(FUNC fptr, int a[], int n)
{
//实现体...
}


3、extern与static


extern和static是C语言中的两个修饰符,extern可用于修饰函数或者变量,表示该变量或者函数在其他文件中进行了定义;
static也可用于修饰函数或者变量,表示该函数或者变量只能在该文件中使用。可利用它们对数据或者函数进行隐藏或者限制访问权限。


三、封装


在C语言中,可以用结构+函数指针来模拟类的实现,而用这种结构定义的变量就是对象。


封装的主要含义是隐藏内部的行为和信息,使用者只用看到对外提供的接口和公开的信息。


有两种方法实现封装:


1、利用C语言语法。在头文件中声明,在C文件中真正定义它。


这样可以隐藏内部信息,因为外部不知道对象所占内存的大小,所以不能静态的创建该类的对象,只能调用类提供的创建函数才能创建。这种方法的缺陷是不支持继承,因为子类中得不到任何关于父类的信息。如:


/**
 * Point的头文件Point.h(对外提供接口)
 */
#ifndef POINT_H
#define POINT_H


extern const void * Point; /* new(Point, x, y); */


void move(void * point, int dx, int dy);


struct Point {
const void * base;  //继承Base类,基类指针,放在第一个位置,const是防止修改
int x, y; //坐标
};


#define point_x(p)(((const struct Point *)(p)) -> x)
#define point_y(p)(((const struct Point *)(p)) -> y)


#endif


 
//Point的源文件Point.c
#include <stdio.h>
#include "Point.h"
#include "cnew.h"
#include "Base.h"


/**********Point类自己的构造函数***********/
static void * Point_New(void * _self, va_list * app) {
struct Point * self = _self;
self->x = va_arg(*app, int);
self->y = va_arg(*app, int);
printf("Point_New self = %p \n", self);
return self;
}


/**********Point类自己的析构函数***********/
static void* Point_Delete(void * _self) {
printf("call Point_Delete self =%p \n", _self);
printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@ \n\n");
return NULL;
}


/**********Point类自己的绘图函数***********/
static void Point_Draw(const void * _self) {
const struct Point * self = _self;
printf("Point_Draw at %d,%d \n", self->x, self->y);
}


void move(void * _self, int dx, int dy) {
struct Point * self = _self;
printf("call move self =%p \n", _self);
self->x += dx;
self->y += dy;
}


static const struct Base _Point = { sizeof(struct Point), Point_New, Point_Delete, Point_Draw };
const void * Point = &_Point;


四、继承


在C语言中,可以利用“结构在内存中的布局与结构的声明具有一致的顺序”这一事实实现继承。


比如我们要设计一个作图工具,其中可能涉及到的对象有Point(点),Circle(圆),由于圆是由点组成的,所有可以看成Circle继承自Point。另外,Point和Circle都需要空间申请,空间释放等操作,所有他们有共同的基类Base。


#ifndef C_NEW_H
#define C_NEW_H


/**
 * 内存管理类头文件cnew.h(对外提供接口)
 */


void * cnew(const void * base, ...);


void cdelete(void * item);


void draw(const void * self);


#endif /* C_NEW_H */


 
/**
 * 内存管理类的源文件:cnew.c
 */
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdarg.h>
#include "cnew.h"
#include "Base.h"


void * cnew(const void * _class, ...) {
const struct Base * base = _class;
void * p = calloc(1, base->size);
assert(p);
*(const struct Base **) p = base;
if (base->constructor) {
va_list ap;
va_start(ap, _class);
p = base->constructor(p, &ap);
va_end(ap);
}
return p;
}


void cdelete(void * self) {
const struct Base ** cp = self;
if (self && *cp && (*cp)->destroy)
self = (*cp)->destroy(self);
free(self);
}


void draw(const void * self) {
const struct Base * const * cp = self;
assert(self && *cp && (*cp)->draw);
(*cp)->draw(self);
}
 
/**
 *  基类Base的内部头文件Base.r,对外隐藏
 */
#ifndef BASE_R
#define BASE_R


#include <stdarg.h>


struct Base {
size_t size;
void * (*constructor)(void * self, va_list * app); //构造函数
void * (*destroy)(void * self);  //析构函数
void (*draw)(const void * self);//作图函数
};


#endif


/**
 * Point的头文件Point.h(对外提供接口)
 */
#ifndef POINT_H
#define POINT_H


extern const void * Point; /* new(Point, x, y); */


void move(void * point, int dx, int dy);


struct Point {
const void * base;  //继承Base类,基类指针,放在第一个位置,const是防止修改
int x, y; //坐标
};


#define point_x(p)(((const struct Point *)(p)) -> x)
#define point_y(p)(((const struct Point *)(p)) -> y)


#endif


//Point的源文件Point.c
#include <stdio.h>
#include "Point.h"
#include "cnew.h"
#include "Base.h"


/**********Point类自己的构造函数***********/
static void * Point_New(void * _self, va_list * app) {
struct Point * self = _self;
self->x = va_arg(*app, int);
self->y = va_arg(*app, int);
printf("Point_New self = %p \n", self);
return self;
}


/**********Point类自己的析构函数***********/
static void* Point_Delete(void * _self) {
printf("call Point_Delete self =%p \n", _self);
printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@ \n\n");
return NULL;
}


/**********Point类自己的绘图函数***********/
static void Point_Draw(const void * _self) {
const struct Point * self = _self;
printf("Point_Draw at %d,%d \n", self->x, self->y);
}


void move(void * _self, int dx, int dy) {
struct Point * self = _self;
printf("call move self =%p \n", _self);
self->x += dx;
self->y += dy;
}


static const struct Base _Point = { sizeof(struct Point), Point_New, Point_Delete, Point_Draw };
const void * Point = &_Point;


/**
 * Circle的头文件Circle.h(对外提供接口)
 */


#ifndef CIRCLE_H
#define CIRCLE_H


#include "Point.h"


extern const void * Circle; /* new(Circle, x, y, rad) */


struct Circle {
const struct Point pbase;  //继承Point类,需放在第一位
int radius;
int (*area)(void *self);// 面积,扩展方法
};


#define circle_area(p) (((const struct Circle *)(p)) -> area(p))


#endif




/**
 * Circle的源文件Circle.c
 */
#include <stdio.h>
#include "Circle.h"
#include "cnew.h"
#include "Base.h"


/**********Circle类自己的扩展函数***********/
static int Circle_Area(void * _self) {
const struct Circle * self = _self;
printf("call Circle_Area self =%p \n", _self);
return self->radius * self->radius;
}


/**********Circle类自己的构造函数***********/
static void * Circle_New(void * _self, va_list * app) {
struct Circle * self = ((const struct Base *) Point)->constructor(_self, app);
self->radius = va_arg(*app, int);
self->area = Circle_Area;
printf("call Circle_New self =%p \n", _self);
return self;
}


/**********Circle类自己的构造函数***********/
static void* Circle_Delete(void * _self) {
printf("call Circle_Delete self =%p \n", _self);
printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@ \n\n");
return NULL;
}


/**********Circle类自己的绘图函数***********/
static void Circle_Draw(const void * _self) {
const struct Circle * self = _self;
int x = point_x(self);
int y = point_y(self);
printf("Circle_Draw at %d,%d rad %d \n", x, y, self->radius);
}


static const struct Base _Circle = { sizeof(struct Circle), Circle_New, Circle_Delete, Circle_Draw };
const void * Circle = &_Circle;






/**
 * 测试函数
 */


#include "Circle.h"
#include "cnew.h"


int oo_main(int argc, char ** argv) {
void * p;
int i;
for (i = 0; i < 2; i++) {
if (i == 0) {
p = cnew(Circle, 1, 2, 3);
circle_area(p);
} else {
p = cnew(Point, 1, 2);
}
draw(p);
move(p, 10, 20);
draw(p);
cdelete(p);
}
return 0;
}


/***********************************
 * 测试结果:
 *
 * Point_New self = 0x50a1d8
 * call Circle_New self =0x50a1d8
 * Circle_Draw at 1,2 rad 3
 * call move self =0x50a1d8
 * Circle_Draw at 11,22 rad 3
 * call Circle_Delete self =0x50a1d8
 *
 * Point_New self = 0x5096a0
 * Point_Draw at 1,2
 * call move self =0x5096a0
 * Point_Draw at 11,22
 * call Point_Delete self =0x5096a0
 *
 ************************************/


五、多态


可以是用C语言中的万能指针void* 实现多态,接上面的例子:


 //测试main.c
 
int oo_main(int argc, char ** argv) {
void * p;
int i;
for (i = 0; i < 2; i++) {
if (i == 0) {
p = cnew(Circle, 1, 2, 3);
circle_area(p);
} else {
p = cnew(Point, 1, 2);
}
draw(p);
move(p, 10, 20);
draw(p);
cdelete(p);
}
return 0;
}


六、总结


C语言能够模拟实现面向对象语言具有的特性,包括:多态,继承,封装等,现在很多开源软件都了用C语言实现了这几个特性,包括大型开源数据库系统postgreSQL,可移植的C语言面向对象框架GObject,无线二进制运行环境BREW。采用C语言实现多态,继承,封装,能够让软件有更好的可读性,可扩展性。


全部的测试代码:


http://download.youkuaiyun.com/detail/andyhuabing/8475335


C语言实现面向对象的原理 编排 |strongerHuang微信公众号 | strongerHuang不知道有多少人去了解过语言的发展史,早期C语言的语法功能其实比较简单。随着应用需求和场景的变化,C语言的语法... 阅读详情

相关推荐

C语言实现面向对象思想编程

附件是在VS2012下用C语言实现面向对象的示例代码,并实现设计模式中的工厂模式

C语言实现面向对象

文章目录一、面向对象的三个基本特征1.1 封装1.2 继承1.3 多态二、C语言实现封装2.1 成员变量定义和访问控制2.2 对象的创建和删除2.3 成员函数的访问控制三、C语言实现继承3.1 子类继承父类成员变量3.2 子类使用父类成员函数四、C语言实现多态4.1 基类中增加虚表指针4.2 虚表的构建和初始化4.3 利用虚表实现多态4.4 代码仓库 一、面向对象的三个基本特征 1.1 封装 封装就是隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别,将抽象得到的数据和行为相结合

qq_36115224的博客 1万+

保姆级教程:从OrthoFinder到CAFE5,手把手搞定基因家族收缩扩张分析(附完整代码与避坑指南)

本文提供从OrthoFinder到CAFE5的基因家族收缩扩张分析全流程教程,涵盖数据预处理、系统发育树准备、CAFE5运行与参数优化等关键步骤。通过详细代码示例和避坑指南,帮助研究者高效完成基因家族进化分析,特别适合生物信息学初学者。

dianshu1593的博客 390

C语言实现面向对象编程 | 干货

本章针对面向对象的封装、继承、组合、多态给出C语言的实现方法。

qq_36075612的博客 3292

高效打卡系统设计:从行为心理学到实践工具

打卡系统作为现代时间管理的重要工具,其核心原理植根于行为心理学中的即时反馈机制和习惯养成理论。通过科学设计的打卡周期和可视化反馈,能有效提升个人自律性和目标达成率。在技术实现上,从纸质记录到数字化工具(如Notion、Excel自动化模板)的演进,为不同场景提供了灵活解决方案。特别在习惯追踪和进度管理领域,结合热力图生成、数据统计等技巧,打卡系统能转化为强大的自我监督工具。本文通过实践案例,详解如何构建兼顾弹性和约束力的个性化打卡方案,帮助读者突破'三天打鱼两天晒网'的常见困境。

weixin_30047059的博客 335

从理论到代码:手把手教你用Matlab复现MMC的HSS阻抗模型(附避坑指南)

本文详细介绍了如何使用Matlab复现MMC的HSS阻抗模型,涵盖谐波状态空间(HSS)理论、代码实现步骤及常见问题解决方案。通过谐波线性化和序阻抗建模技术,帮助工程师准确分析MMC的阻抗特性,并提供避坑指南以解决矩阵维度错误、收敛性问题和频域转换陷阱等难点。

weixin_42561040的博客 356

C语言这样来实现面向对象

关注、星标公众号,直达精彩内容来源链接:https://blog.youkuaiyun.com/onlyshi/article/details/81672279不知道有多少人去了解过语言的发展史,早期C语言的语法功能其实比较简单。随着应用需求和场景的变化,C语言的语法功能在不断升级变化。虽然我们的教材有这么一个结论:C语言是面向过程的语言,C++是面向对象的编程语言,但面向对...

李肖遥的专栏 1943

机场数据治理系列介绍(1):机场行业数据中台中的数据管理顶层设计方案

民航机场行业的数据中台中,有关数据管理顶层设计方案需要结合机场行业的业务特点和技术需求进行具体的设计,今日我们简要考量设计提供一个参考方案:

机场信息系统研究员的专栏 1604

用c语言实现面向对象,用C语言实现面向对象

1、 概述C语言是一种面向过程的程序设计语言,而C++是在C语言基础上衍生来了的面向对象的语言,实际上,很多C++实现的底层是用C语言实现的,如在Visual C++中的Interface其实就是struct,查找Interface的定义,你可以发现有这样的宏定义:#ifndef Interface#define Interface struct#endifC++在语言级别上添加了很多新机制(继...

weixin_31809171的博客 1330

【win10+RAGFlow+Ollama】搭建本地大模型助手(教程+源码)

在当今科技飞速发展的时代,人工智能(AI)已经成为各行各业不可或缺的一部分。特别是在文档处理和数据分析领域,AI的应用更是无处不在。今天,我要向大家介绍一个开源的AI框架引擎——RAGflow。它能够在深度文档理解方面执行检索增强生成(Retrieval-Augmented Generation,简称RAG),并且被认为是目前最优秀的RAG框架之一。本文将详细探讨RAGflow的创新功能、技术特点以及如何在实际应用中发挥其最大潜力。

Yooao的博客 9617

使用 MATLAB/Simulink + Simscape Electrical,构建一个含储能的微电网系统,实现储能系统与并网逆变器的协同控制

摘要:本文基于Simulink平台,详细介绍了微电网中储能系统与并网逆变器的协同控制建模与仿真方法。主要内容包括:1)构建包含光伏、风电、锂电池和双向DC-DC变换器的微电网系统;2)设计并网逆变器的PQ/Vf双模式控制策略;3)实现储能系统与逆变器的协同控制逻辑,包括SOC保护和功率分配;4)通过多种工况仿真验证系统性能。结果表明,该系统能有效维持微电网稳定运行,支持并网/离网无缝切换。文章还探讨了优化方向和应用扩展,为新能源微电网控制提供了实用参考。

xiaoheshang_123的博客 100

C语言实现【面向对象】的一些方法

关注+星标公众号,不错过精彩内容编排 |strongerHuang微信公众号 | strongerHuang不知道有多少人去了解过语言的发展史,早期C语言的语法功能其实比较简单。随着应用需求和场景的变化,C语言的语法功能在不断升级变化。虽然我们的教材有这么一个结论:C语言是面向过程的语言,C++是面向对象的编程语言,但面向对象的概念是在C语言阶段就有了,而且应用到了很多地方,比如某些操作系统内核...

strongerHuang 1391

【技能】OpenClaw Skills学习及手搓一个极简skill

本文介绍了OpenClaw Skills的基础概念与使用方法。Skills是OpenClaw代理使用工具的核心载体,通过SKILL.md文件定义技能属性和执行方式。技能加载遵循"工作区>本地>内置>自定义目录"的优先级规则。用户可通过ClawHub一键安装现成技能,也可自定义开发技能:创建技能目录,编写包含YAML元数据和执行指令的SKILL.md文件,放置于工作区skills目录进行测试。文章还介绍了多代理场景下的技能共享、插件集成以及安全注意事项,包括沙箱使用和敏感

海兰 3974

C 语言实现面向对象编程

C 语言实现面向对象编程 1、引言 面向对象编程(OOP)并不是一种特定的语言或者工具,它只是一种设计方法、设计思想。它表现出来的三个最基本的特性就是封装、继承与多态。很多面向对象的编程语言已经包含这三个特性了,例如 Smalltalk、C++、Java。但是你也可以用几乎所有的编程语言来实现面向对象编程,例如 ANSI-C。要记住,面向对象是一种思想,一种方法,不要太拘泥于编程语言。...

onlyshi的专栏 6万+

YOLOv26详解 | 一文带你从代码角度深入理解ultralytics最新作品yolov26的创新 | 训练、推理、验证、导出 (附网络结构图PPT可用,全网最全)

YOLOv26带来多项创新:1)采用双检测头机制(One-to-Many和One-to-One)实现端到端无NMS推理;2)移除DFL简化边界框回归;3)引入ProgLoss+STAL优化小目标检测;4)使用MuSGD优化器提升训练稳定性。网络结构方面,SPPF模块增加shortcut连接,并在C3k2中引入PSABlock注意力机制。该版本更注重实际部署,简化了推理流程,提升硬件兼容性。教程涵盖模型训练、验证、推理及导出全流程,支持多种格式转换如ONNX、TensorRT等,适合工业应用场景。

Snu77的博客 4060

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

C实现面向对象

C实现面向对象编程

pythom_aaa的博客 586

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

C和C++的面向对象专题(2)——C语言也能实现面向对象

C语言的面向对象设计方法,正如题记上面所说,面向对象是一种思想,而并非是一种语言,我们将会介绍C语言实现的面向对象开发方式。

西风世界 2711

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

c语言如何实现面向对象编程

一、简介 C语言是面向过程的一门语言,C++是面向对象,这个特性早已深入人心。但是嵌入式底层以及大型操作系统等却都是用C开发的。如果只用面向过程去开发这类大型软件,肯定行不通。 因此,C语言也可以用面向对象的思维去开发。例如现在的STM32的HAL库就在向着这个趋势进发。 二、 C语言实现封装 大部分使用 C 语言进行开发的工程师,在接触更高级的编程语言之前...

qq_27726651的博客 4932

C语言实现面向对象的原理~

不知道有多少人去了解过语言的发展史,早期C语言的语法功能其实比较简单。随着应用需求和场景的变化,C语言的语法功能在不断升级变化。虽然我们的教材有这么一个结论:C语言是面向过程的语言,C+...

372

如何在C语言里实现“面向对象编程”

有人认为面向对象是C++/Java这种高级语言的专利,实际不是这样,面向对象作为一种设计方法,是不限制语言的。只能说,用C++/Java这种语法来实现面向对象会更容易、更自然一些。 在本节中,就展示如何在C语言中实现面向对象编程,这是一件吃力的工作。写这些的目的有两个: ① 更好的掌握C++中的class的概念。学习了本章,就知道C程序员的无耐,就知道为什么要发明一个class的概念、为什么要

阿发你好 7203

硬核,用C语言实现面向对象!!!

用C语言实现面向对象,听起来就有不可思议的感觉,那真的可以实现吗?我觉得OK! 要使用C语言这种面向过程的语言来实现面向对象,首先要做的事情是去了解面向对象是怎样的概念,列:继承的本质是怎样的一回事,多态又是怎么来的。 在面向对象语言中,继承通过子类声明为某个父类的继承,在C++中,继承的方式有public 继承,private 继承,protected 继承,分别为公有继承,私有继承,保护继承,...

Dream136的博客 711

C语言实现面向对象设计

面向对象设计有诸多优势:可读性强,扩展性强,复用性强。 面向对象语言有3大核心技术: 1、封装性 2、继承性 3、多态性 主流面向对象编程语言有:java ,c++ , python。很遗憾C语言并不是一个面向对象的语言,但是这并不影响C语言的强大,介绍两个C语言的强大的应用场景:操作系统内核设计,编译器设计。虽然C语言不是面向对象编程语言,但是通过一些设计技巧可以实现面向对象设计。接下来我们研究一下如何用C语言实现面向对象设计,本文将用JAVA语言和C语言进行讲解。 封装性 封装是面向对象编程的核心思想。

li_man_man_man的博客 5133

C语言实现面向对象的方法详解

还是那句话,面向对象编程是一种方法,并不局限于某一种编程语言。用 C 语言实现封装、单继承,理解和实现起来比较简单,多态反而会稍微复杂一点,如果打算广泛的使用多态,还是推荐转到 C++ 语言上,毕竟这层复杂性被这个语言给封装了,你只需要简单的使用就行了。但并不代表,C 语言实现不了多态这个特性。

随手写下笔记和感悟 1626
上一篇: 软件设计本质论(Essential Design)—白话面向对象
下一篇: 高级系统架构师培训笔记
andyhuabing
博客等级 码龄19年 704粉丝 165原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值