当前位置: 首页 > news >正文

用c实现C++类(八股)

在 C 语言中,虽然没有内建的面向对象编程(OOP)特性(如封装、继承、多态),但通过一些编程技巧,我们仍然可以模拟实现这些概念。下面将用通俗易懂的方式,逐步介绍如何在 C 中实现封装、继承和多态。

1. 封装(Encapsulation)

封装是指将数据和操作数据的函数绑定在一起,隐藏内部实现细节,只暴露必要的接口。在 C 中,我们可以通过 struct 和相关的函数来实现封装。

假设我们要创建一个“矩形”对象,包含宽度和高度,并提供计算面积的功能。

步骤:

  1. 定义结构体(隐藏内部细节)
  2. 提供创建和操作该结构体的函数

实现:

// Rectangle.h
#ifndef RECTANGLE_H
#define RECTANGLE_Htypedef struct Rectangle Rectangle;// 创建矩形
Rectangle* Rectangle_create(double width, double height);// 销毁矩形
void Rectangle_destroy(Rectangle* rect);// 计算面积
double Rectangle_getArea(const Rectangle* rect);#endif // RECTANGLE_H// Rectangle.c
#include <stdlib.h>
#include "Rectangle.h"// 定义结构体(隐藏在 .c 文件中)
struct Rectangle {double width;double height;
};// 创建矩形
Rectangle* Rectangle_create(double width, double height) {Rectangle* rect = (Rectangle*)malloc(sizeof(Rectangle));if (rect != NULL) {rect->width = width;rect->height = height;}return rect;
}// 销毁矩形
void Rectangle_destroy(Rectangle* rect) {free(rect);
}// 计算面积
double Rectangle_getArea(const Rectangle* rect) {if (rect == NULL) return 0.0;return rect->width * rect->height;
}// main.c
#include <stdio.h>
#include "Rectangle.h"int main() {Rectangle* rect = Rectangle_create(5.0, 3.0);if (rect != NULL) {printf("面积: %.2f\n", Rectangle_getArea(rect));Rectangle_destroy(rect);}return 0;
}

说明:

  • 隐藏实现Rectangle 的具体结构体定义在 Rectangle.c 中,外部无法直接访问其成员变量。
  • 接口函数:通过 Rectangle_createRectangle_destroyRectangle_getArea 提供对 Rectangle 对象的操作。

2. 继承(Inheritance)

继承允许一个“子类”拥有“父类”的属性和行为。在 C 中,我们可以通过在子结构体中包含父结构体来模拟继承。

基类“形状”和子类“矩形”和“圆形”

步骤:

  1. 定义基类结构体,包含一个指向函数的指针(模拟虚函数表)。
  2. 定义子类结构体,在其中包含基类结构体。
  3. 实现子类的功能

实现:

// Shape.h
#ifndef SHAPE_H
#define SHAPE_Htypedef struct Shape Shape;// 虚函数表
typedef struct {double (*getArea)(const Shape* self);void (*destroy)(Shape* self);
} ShapeVTable;// 基类结构体
struct Shape {ShapeVTable* vtable;
};// 基类接口函数
double Shape_getArea(const Shape* self);
void Shape_destroy(Shape* self);#endif // SHAPE_H// Shape.c
#include "Shape.h"double Shape_getArea(const Shape* self) {if (self && self->vtable && self->vtable->getArea) {return self->vtable->getArea(self);}return 0.0;
}void Shape_destroy(Shape* self) {if (self && self->vtable && self->vtable->destroy) {self->vtable->destroy(self);}
}// Rectangle.h
#ifndef RECTANGLE_H
#define RECTANGLE_H#include "Shape.h"typedef struct {Shape base; // 继承自 Shapedouble width;double height;
} Rectangle;// 创建矩形
Shape* Rectangle_create(double width, double height);#endif // RECTANGLE_H// Rectangle.c
#include <stdlib.h>
#include "Rectangle.h"// 矩形的虚函数实现
double Rectangle_getArea(const Shape* self) {const Rectangle* rect = (const Rectangle*)self;return rect->width * rect->height;
}void Rectangle_destroy_impl(Shape* self) {free(self);
}// 定义矩形的虚函数表
ShapeVTable rectangle_vtable = {.getArea = Rectangle_getArea,.destroy = Rectangle_destroy_impl
};// 创建矩形
Shape* Rectangle_create(double width, double height) {Rectangle* rect = (Rectangle*)malloc(sizeof(Rectangle));if (rect != NULL) {rect->base.vtable = &rectangle_vtable;rect->width = width;rect->height = height;}return (Shape*)rect;
}// Circle.h
#ifndef CIRCLE_H
#define CIRCLE_H#include "Shape.h"typedef struct {Shape base; // 继承自 Shapedouble radius;
} Circle;// 创建圆形
Shape* Circle_create(double radius);#endif // CIRCLE_H// Circle.c
#include <stdlib.h>
#include "Circle.h"
#include <math.h>// 圆形的虚函数实现
double Circle_getArea(const Shape* self) {const Circle* circle = (const Circle*)self;return M_PI * circle->radius * circle->radius;
}void Circle_destroy_impl(Shape* self) {free(self);
}// 定义圆形的虚函数表
ShapeVTable circle_vtable = {.getArea = Circle_getArea,.destroy = Circle_destroy_impl
};// 创建圆形
Shape* Circle_create(double radius) {Circle* circle = (Circle*)malloc(sizeof(Circle));if (circle != NULL) {circle->base.vtable = &circle_vtable;circle->radius = radius;}return (Shape*)circle;
}// main.c
#include <stdio.h>
#include "Shape.h"
#include "Rectangle.h"
#include "Circle.h"int main() {Shape* shapes[2];shapes[0] = Rectangle_create(5.0, 3.0); // 创建矩形shapes[1] = Circle_create(2.0);         // 创建圆形for (int i = 0; i < 2; ++i) {printf("图形 %d 的面积: %.2f\n", i + 1, Shape_getArea(shapes[i]));Shape_destroy(shapes[i]);}return 0;
}

说明:

  • 基类 Shape:包含一个虚函数表 vtable,用于指向具体实现的函数。
  • 子类 RectangleCircle
    • 包含 Shape 作为第一个成员,实现“继承”。
    • 定义自己的虚函数(如 getAreadestroy_impl)。
    • 分别创建自己的虚函数表,并在创建时将 vtable 指向自己的表。
  • 多态:在 main 中,通过基类指针 Shape* 调用 getArea,根据实际对象类型(矩形或圆形)执行不同的函数。

3. 多态(Polymorphism)

多态允许不同类型的对象通过相同的接口调用不同的实现。在上面的继承示例中,我们已经部分实现了多态。下面进一步解释多态的实现。

Shape 基类中定义了虚函数表 ShapeVTable,包含 getAreadestroy 函数指针。每个子类(如 RectangleCircle)都提供了自己的实现,并在创建时将 vtable 指向自己的函数表。

如何工作:

  1. 统一接口:所有形状都通过 Shape* 指针进行操作。
  2. 具体实现:不同的形状(矩形、圆形)有各自的 getArea 实现。
  3. 调用时自动选择:根据对象的实际类型,调用相应的 getArea 函数。

示例解释:

for (int i = 0; i < 2; ++i) {printf("图形 %d 的面积: %.2f\n", i + 1, Shape_getArea(shapes[i]));Shape_destroy(shapes[i]);
}
  • Shape_getArea(shapes[i]) 会根据 shapes[i]vtable 指向不同的 getArea 实现,自动计算出矩形或圆形的面积。

相关文章:

用c实现C++类(八股)

在 C 语言中&#xff0c;虽然没有内建的面向对象编程&#xff08;OOP&#xff09;特性&#xff08;如封装、继承、多态&#xff09;&#xff0c;但通过一些编程技巧&#xff0c;我们仍然可以模拟实现这些概念。下面将用通俗易懂的方式&#xff0c;逐步介绍如何在 C 中实现封装、…...

【C++多线程编程:六种锁】

目录 普通互斥锁&#xff1a; 轻量级锁 独占锁&#xff1a; std::lock_guard&#xff1a; std::unique_lock: 共享锁&#xff1a; 超时的互斥锁 递归锁 普通互斥锁&#xff1a; std::mutex确保任意时刻只有一个线程可以访问共享资源&#xff0c;在多线程中常用于保…...

【Javascript Day5】for循环及典型案例

for 循环 // 语法&#xff1a; for( 开始 ; 结束 ; 步长 ){ 循环体 } // for( var i 循环初始值 ; i的循环范围 ; i的增加或减少规则 ){ 循环体 } // 死循环 // for(;;){ // console.log("for循环"); // } // 循环打…...

#渗透测试#网络安全#一文了解什么是shell反弹!!!

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…...

《解锁图像的语言密码:Image Caption 开源神经网络项目全解析》

《解锁图像的语言密码&#xff1a;Image Caption 开源项目全解析》 一、开篇&#xff1a;AI 看图说话时代来临二、走进 Image Caption 开源世界三、核心技术拆解&#xff1a;AI 如何学会看图说话&#xff08;一&#xff09;深度学习双雄&#xff1a;CNN 与 RNN&#xff08;二&a…...

抢占欧洲电商高地,TikTok 运营专线成 “秘密武器”

在当今数字化浪潮席卷全球的时代&#xff0c;社交媒体平台已成为商业拓展的关键阵地&#xff0c;TikTok 更是其中的闪耀新星。近日&#xff0c;一则重磅消息引发行业关注&#xff1a;TikTok 正计划于 2025 年初进军荷兰电商市场。这一战略布局&#xff0c;不仅彰显了 TikTok 对…...

人工智能-数据分析及特征提取思路

1、概况 基于学生行为数据预测是否涉黄、涉黑等。 2.数据分析 数据分析的意义包括得到数据得直觉、发掘潜在的结构、提取重要的变量、删除异常值、检验潜在的假设和建立初步的模型。 2.1数据质量分析 2.1.1数据值分析 查看数据类型&#xff1a; 首先明确各字段的数据类型…...

2024 China Collegiate Programming Contest (CCPC) Zhengzhou Onsite 基础题题解

今天先发布基础题的题解&#xff0c;明天再发布铜牌题和银牌题的题解 L. Z-order Curve 思路&#xff1a;这题目说了&#xff0c;上面那一行&#xff0c;只有在偶数位才有可能存在1&#xff0c;那么一定存在这样的数&#xff0c;0 ,1,100, 10000,那么反之&#xff0c;我们的数…...

halcon3d 如何计算平面法向量!确实很简单

这个问题其实一直困扰了我很长时间,之前是怎么算的呢 对于一个平面,我会先求它的fit_primitives_object_model_3d去将它拟合,接下来用surface_normals_object_model_3d 算子生成它的法线,后用get_object_model_3d_params (ObjectModel3DNormals, ‘point_normal_x’, GenP…...

浅尝Appium自动化框架

浅尝Appium自动化框架 Appium自动化框架介绍Appium原理Appium使用安装平台驱动实战 坑 Appium自动化框架介绍 Appium 是一个开源的自动化测试框架&#xff0c;最初设计用于移动应用的测试&#xff0c;但现在它也扩展了对桌面端应用的支持。Appium 使得自动化测试变得更加简单&…...

网络安全测评技术与标准

网络安全测评概况 网络安全测评是网络信息系统和IT技术产品的安全质量保障。本节主要阐述网络安全测评的概念&#xff0c;给出网络安全测评的发展状况。 18.1.1 网络安全测评概念 网络安全测评是指参照一定的标准规范要求&#xff0c;通过一系列的技术和管理方法&#xff0c;获…...

【经典神经网络架构解析篇】【1】LeNet网络详解:模型结构解析、优点、实现代码

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…...

KGA:AGeneral Machine Unlearning Framework Based on Knowledge Gap Alignment

文章目录 摘要1 引言2 相关工作3 符号与定义4 我们的 KGA 框架4.1 KGA框架知识差距对齐目标 4.2 KGA在自然语言处理任务中的应用文本分类机器翻译响应生成 5 实验设置数据集评估指标参数设置比较方法 6 实验结果6.1 主要比较结果6.2 KGA 的优越性分析降低语言模型概率比较 6.3 …...

GelSight Mini视触觉传感器凝胶触头升级:增加40%耐用性,拓展机器人与触觉AI 应用边界

马萨诸塞州沃尔瑟姆-2025年1月6日-触觉智能技术领军企业Gelsight宣布&#xff0c;旗下Gelsight Mini视触觉传感器迎来凝胶触头的更新。经内部测试&#xff0c;新Gel凝胶触头耐用性提升40%&#xff0c;外观与触感与原凝胶触头保持一致。此次升级有效满足了客户在机器人应用中对设…...

springboot整合admin

1. 添加依赖 首先&#xff0c;在你的admin服务端pom.xml文件中添加Spring Boot Admin的依赖&#xff1a; <dependency><groupId>de.codecentric</groupId><artifactId>spring-boot-admin-starter-server</artifactId><version>2.5.4<…...

OS--常见的网络模型(包含IO多路复用的原理)

网络模型 IO模型主要就是用户空间和内核空间数据交换的形式。 IO模型 阻塞 I/O 模型&#xff08;Blocking I/O&#xff09; 应用程序发起 I/O 请求后&#xff0c;会被阻塞&#xff0c;直到 I/O 操作完成。 非阻塞 I/O 模型&#xff08;Non-blocking I/O&#xff09; 应用程序…...

LCE(Local Cascade Ensemble)预测模型和LSTM(Long Short-Term Memory)模型在效果和特点上存在显著差异

LCE&#xff08;Local Cascade Ensemble&#xff09;预测模型和LSTM&#xff08;Long Short-Term Memory&#xff09;模型在效果和特点上存在显著差异。以下是对两者的比较&#xff1a; 一、效果比较 LCE模型&#xff1a; 优势&#xff1a;LCE结合了随机森林和XGBoost的优势&a…...

【mysql】约束的基本使用

文章目录 1. PRIMARY KEY 约束1.1 作用1.2 关键字1.3 特点1.4 添加主键约束1.5 关于复合主键1.6 删除主键约束 2. 自增列&#xff1a;AUTO_INCREMENT2.1 作用2.2 关键字2.3 特点和要求2.4 如何指定自增约束2.5 如何删除自增约束2.6 MySQL 8.0新特性—自增变量的持久化 3. FOREI…...

EasyExcel(二)导出Excel表自动换行和样式设置

EasyExcel(一)导出Excel表列宽自适应 背景 在上一篇文章中解决导出列宽自适应,然后也解决了导出列宽不可超过255的问题。但是实际应用场景中仍然会有导出数据的长度超过列宽255。这时导出效果就会出现如下现象: 多出列宽宽度的内容会浮出来,影响后边列数据的显示。 解决…...

农产品直播带货方案拆解

作为一名经验丰富的营销策划人道叔&#xff0c;今天我来拆解一下咱们4A营销广告圈的这份《直播天府川农好物带货方案》&#xff0c;让你能学到很多实用的策略和技巧&#xff0c;直接应用到你的策划工作中去。 首先&#xff0c;咱们看看背景分析。 助农直播现在可是个大热门&a…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

Netty从入门到进阶(二)

二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架&#xff0c;用于…...

MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释

以Module Federation 插件详为例&#xff0c;Webpack.config.js它可能的配置和含义如下&#xff1a; 前言 Module Federation 的Webpack.config.js核心配置包括&#xff1a; name filename&#xff08;定义应用标识&#xff09; remotes&#xff08;引用远程模块&#xff0…...