C语言实现面向对象

一、引言

面向对象编程(OOP)是一种程序设计范型,它使用“对象”来设计应用程序和系统的结构行为。虽然C语言本身并不直接支持面向对象编程,但我们可以使用结构体(struct)和 函数指针(function pointers)来模拟面向对象的一些特性,如封装、继承和多态。

二、模拟面向对象特性

封装

定义

封装是将数据和操作数据的方法  绑定在一起的一种机制。在C语言中,我们可以使用结构体来封装数据,并使用结构体中的函数指针来封装方法。

示例:

typedef struct { 
int x; 
int y; 
void (*move)(struct Point*, int, int); 
} Point; void movePoint(Point* self, int dx, int dy) { 
self->x += dx; 
self->y += dy; 
} int main() { 
Point p = {0, 0, movePoint}; 
p.move(&p, 10, 5); 
printf("(%d, %d)\n", p.x, p.y); // 输出 (10, 5) 
return 0; 
}
 

在C语言中模拟继承通常涉及结构体嵌套和函数指针的使用。但请注意,C语言中的继承并不如面向对象语言中的那么强大和灵活。

示例(模拟简单的继承关系):

typedef struct Base { void (*print)(struct Base*); } Base; void basePrint(Base* self) { printf("Base class\n"); } typedef struct Derived { Base base; void (*specialPrint)(struct Derived*); } Derived; void derivedPrint(Derived* self) { self->base.print((Base*)self); // 调用基类方法 printf("Derived class\n"); } int main() { Derived d = {{basePrint}, derivedPrint}; d.specialPrint(&d); // 输出 Base class 和 Derived class return 0; }

继承

定义:

在C语言中模拟继承通常涉及结构体嵌套和函数指针的使用。但请注意,C语言中的继承并不如面向对象语言中的那么强大和灵活。

示例

typedef struct Base {  void (*print)(struct Base*);  
} Base;  void basePrint(Base* self) {  printf("Base class\n");  
}  typedef struct Derived {  Base base;  void (*specialPrint)(struct Derived*);  
} Derived;  void derivedPrint(Derived* self) {  self->base.print((Base*)self);  // 调用基类方法  printf("Derived class\n");  
}  int main() {  Derived d = {{basePrint}, derivedPrint};  d.specialPrint(&d);  // 输出 Base class 和 Derived class  return 0;  
}

多态

定义

多态是面向对象编程中的一个重要概念,它允许不同的对象对同一消息做出不同的响应。在C语言中模拟多态通常涉及函数指针和类型转换。但C语言中的多态实现相对复杂,且容易出错。

在C语言中实现真正的多态(像C++中的动态绑定)是相当复杂的,因为C语言不支持运行时类型信息(RTTI)或虚函数表(vtable)。然而,我们可以模拟一种有限形式的多态,通过函数指针数组或者“接口”类型的结构体。

下面是一个使用函数指针数组来模拟多态的简单示例:

 
#include <stdio.h>  // 定义一个“接口”结构体,包含函数指针  
typedef struct {  void (*display)(void);  
} Shape;  // 圆形结构体,包含接口函数指针的实现  
typedef struct {  Shape base; // 继承自Shape接口  double radius;  
} Circle;  // 矩形结构体,包含接口函数指针的实现  
typedef struct {  Shape base; // 继承自Shape接口  double width;  double height;  
} Rectangle;  // 圆形display方法的实现  
void circle_display(Circle *c) {  printf("Circle with radius %.2f\n", c->radius);  
}  // 矩形display方法的实现  
void rectangle_display(Rectangle *r) {  printf("Rectangle with width %.2f and height %.2f\n", r->width, r->height);  
}  // 一个函数,接受Shape接口指针并调用其display方法  
void display_shape(Shape *shape) {  shape->display(); // 注意这里并没有直接的类型检查,是静态分派的  
}  // 初始化圆形并设置接口方法  
void init_circle(Circle *c, double radius) {  c->radius = radius;  c->base.display = (void (*)(void))circle_display; // 强制类型转换,因为C没有类型安全的函数指针  
}  // 初始化矩形并设置接口方法  
void init_rectangle(Rectangle *r, double width, double height) {  r->width = width;  r->height = height;  r->base.display = (void (*)(void))rectangle_display; // 同样需要强制类型转换  
}  int main() {  // 创建圆形和矩形对象,并初始化它们  Circle circle;  Rectangle rectangle;  init_circle(&circle, 5.0);  init_rectangle(&rectangle, 4.0, 6.0);  // 将它们作为Shape接口进行显示  display_shape((Shape *)&circle);    // 输出:Circle with radius 5.00  display_shape((Shape *)&rectangle); // 输出:Rectangle with width 4.00 and height 6.00  return 0;  
}

在这个例子中,我们创建了一个Shape结构体作为“接口”,它包含一个函数指针display。然后我们有两个具体的形状类型CircleRectangle,它们都包含了一个Shape类型的成员作为它们的“基类”部分。我们使用函数指针来模拟虚函数,并在初始化对象时设置这些函数指针。display_shape函数接受一个Shape指针,并调用它的display方法,实现了多态的效果(尽管是静态分派的)。

但是,请注意,由于C语言不支持动态绑定,这里的display调用是静态分派的,这意味着在编译时就已经确定了调用哪个函数。真正的动态多态需要运行时类型信息和虚函数表,这在C语言中是不可用的。上面的示例只是一种模拟,它依赖于程序员在运行时正确地设置函数指针。

总结

虽然C语言本身并不直接支持面向对象编程,但我们可以使用结构体和函数指针来模拟面向对象的一些特性。然而,这种模拟通常比真正的面向对象语言更加复杂和繁琐,且容易出错。因此,在需要使用面向对象特性的情况下,通常建议使用专门的面向对象语言(如C++、Java或Python)来编写代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/8048.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

上市公司财务困境模型​MertonDD、OScore、RLPM、ZScore四种模型​(1992-2022年)

01、数据介绍 上市公司财务困境模型是用于预测和评估上市公司是否可能陷入财务困境的一种模型。这个模型通常基于一系列的财务比率和其他相关变量&#xff0c;通过统计分析方法来构建。​ 数据名称&#xff1a;上市公司财务困境模型MertonDD、OScore、RLPM、ZScore五种模型 …

vue2 阻止控制台报错

在Vue 2中&#xff0c;如果你想要阻止控制台中的某些错误报告&#xff0c;你可以使用Vue.config.errorHandler来全局处理错误&#xff0c;从而避免控制台输出这些错误。 例如&#xff0c;你可以在Vue应用的入口文件&#xff08;比如main.js&#xff09;中添加以下代码&#xf…

电脑提示mfc140u.dll文件丢失了?怎么快速修复mfc140u.dll文件

当你的电脑提示你的mfc140u.dll文件丢失了&#xff0c;那么就要小心了&#xff0c;可能你的某些程序出问题了&#xff01;这时候需要我们去进行相关的修复&#xff0c;只有修复了这个mfc140u.dll文件&#xff0c;才能正常的使用某些程序。下面一起来了解一下mfc140u.dll文件吧。…

download_file、download

download_file源码 def download_file(url: str, fname: str, chunk_size1024):"""Helper function to download a file from a given url"""resp requests.get(url, streamTrue)total int(resp.headers.get("content-length", 0))…

C++中erase函数的用法

在C中&#xff0c;erase函数用于从容器中删除一个或一系列元素。它通常用于删除容器中的指定位置的元素或特定值的元素。 erase函数通常有两种用法&#xff1a; 删除指定位置的元素&#xff1a;erase(iterator position) 这种用法会删除容器中迭代器position指向的元素。 st…

uni-app安卓本地打包个推图标配置

如果什么都不配置&#xff0c;默认的就是个推小鲸鱼图标 默认效果 配置成功效果 个推图标配置 新建目录 drawable-hdpi、drawable-ldpi、drawable-mdpi、drawable-xhdpi、drawable-xxhdpi、drawable-xxxhdpi 目录中存放图标 每个目录中存放对应大小的图标&#xff0c;大图…

Oracle到PostgreSQL的不停机数据库迁移

1970 年&#xff0c;数据库之父 Edgar Frank Codd 发表了“数据的关系模型”论文&#xff0c;该论文为往后的关系型数据库的发展奠定了基础。1979 年&#xff0c;基于关系模型理论的数据库产品 Oracle 2 首次亮相&#xff0c;并在过去的三四十年时间里&#xff0c;横扫全球数据…

【C++风云录】创新编程:艺术生成与计算艺术

揭秘C创意编程库: 开源创意编码的艺术生成 前言 在现代软件开发中&#xff0c;C库的使用越来越广泛。这些库包括图形处理、音频处理、编程接口以及机器学习等多个领域&#xff0c;极大地方便了开发者创意编程和开发高质量的应用程序。本文将详细介绍六个重要的C库&#xff1a…

什么是web3D?应用场景有哪些?如何实现web3D展示?

Web3D是一种将3D技术与网络技术完美结合的全新领域&#xff0c;它可以实现将数字化的3D模型直接在网络浏览器上运行&#xff0c;从而实现在线交互式的浏览和操作。 Web3D通过将多媒体技术、3D技术、信息网络技术、计算机技术等多种技术融合在一起&#xff0c;实现了它在网络上…

浏览器各类好用插件使用及常见问题(技巧)总结

目录 Vimium C快捷键问题为什么Vimium C - 全键盘操作浏览器插件在百度页面中, x ,o,f等快捷键不起作用如何使用viminum c插件进行自定义快捷键?vimucm 为什么在浏览器首页时快捷键不起作用? 网页截图问题firefox 网页截图使用 idm问题浏览器点击idm 不下载? 待续、更新中 V…

oracle数据归档方案

1、查询现有表空间数据量; -- system: 查询表空间使用情况 SELECT upper(f.tablespace_name) "Tablespace_name", round((d.Tot_grootte_Mb - f.total_bytes) / d.Tot_grootte_Mb * 100,2) " Used (%) ", round(f.total_bytes / d.Tot_groo…

23_Scala集合Set

文章目录 Set1.构建方式2.可变Set集合3.可变集合的增删改查 Set –无序,数据不可重复集合 –Set是特质&#xff0c;不能直接构建&#xff0c;默认是不可变集合 1.构建方式 // 1.构建方式 val set Set.apply(2,2,2,2,3,4,5) println(set) //Set(2, 3, 4, 5)2.可变Set集…

Hadoop3:HDFS的架构组成

一、官方文档 我这里学习的是Hadoop3.1.3版本&#xff0c;所以&#xff0c;查看的也是3.1.3版本的文档 Architecture模块最下面 二、HDFS架构介绍 HDFS架构的主要组成部分&#xff0c;是一下四个部分 1、NameNode(NN) 就是Master节点&#xff0c;它是集群管理者。 1、管…

CSS 样式清单整理:文字超出部分显示省略号和设置placeholder的字体样式

单行文本的溢出显示省略号&#xff08;一定要有宽度&#xff09; p{width:200rpx;overflow: hidden;text-overflow:ellipsis;white-space: nowrap;}多行文本溢出显示省略号 p {display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 3;overflow: hidden;}设…

word格式技巧

文章目录 论文格式技巧论文交叉引用怎么弄论文的页码怎么弄 论文格式技巧 论文交叉引用怎么弄 1.取消文献原有的编号 2.定义新编号 3.具体编号设置 4.在引用的地方插入&#xff0c;具体引用选项卡–>交叉引用–>选择后插入 2. 4. 论文的页码怎么弄 假设我们有这样一…

Rust 常用 Web 开源代码库

Rust的web开发有许多优秀的开源库可供选择&#xff0c;以下是一些值得关注的库&#xff1a; Web框架&#xff1a; Axum&#xff1a;由Rust社区的异步事实标准Tokio团队开发&#xff0c;以高性能和强大的异步支持著称。其特点包括使用无宏API将请求路由到处理程序、使用提取器以…

Oracle完整截取汉字的方法

在Oracle数据库中&#xff0c;要完整截取汉字&#xff0c;你通常应该使用SUBSTR函数而不是SUBSTRB函数&#xff0c;因为SUBSTRB是基于字节进行截取的&#xff0c;而汉字在UTF-8等编码中通常占用多个字节。使用SUBSTR则能确保按照字符来截取&#xff0c;从而避免截断汉字。 SUB…

Nginx内存池源码刨析

Nginx 内存池刨析 实例源码刨析 #define BLOCK_SIZE 16 //每次分配内存块大小#define MEM_POOL_SIZE (1024 * 4) //内存池每块大小int i 0, k 0;int use_free 0;ngx_pagesize getpagesize();//获取系统的页大小//printf("pagesize: %zu\n",ngx_pagesize);ch…

SpringBoot @DS注解 和 DynamicDataSource自定义实现多数据源的2种实现方式

前言 在实际的项目中&#xff0c;我们经常会遇到需要操作多个数据源的情况&#xff0c;SpringBoot为我们提供了多种实现多数据源的方式。本文将介绍两种常见的方式&#xff1a;使用DS注解实现多数据源的切换以及使用DynamicDataSource自定义实现多数据源的切换。 我们将分别介…

LINUX 入门 9

LINUX 入门 9 day11 20240507 耗时&#xff1a;120min 课程链接地址 第9章 百万并发的服务器 1 百万并发项目介绍与并发概念讲解 书接上回&#xff0c;把server做成并发量百万级的服务量 装4台虚拟机 vmware右下角可以设置虚拟机内存 内核 没敲&#xff0c;就看了一下&a…