首页 > 其他分享 >在C语言中使用OOP

在C语言中使用OOP

时间:2024-02-16 22:22:41浏览次数:35  
标签:int void timer stack OOP 使用 C语言 Stack size

前言

这几天正在学习C++, 学到了面向对象, 突然想到前几天写的期末项目, 自己就已经潜移默化的运用了面向对象的思想. 于是就开始思考, 能否在C语言中实现面向对象编程. C语言本身不支持面向对象, 这给实现过程带来了很多的麻烦, 但好在也能通过一些方法硬造出来.

类和对象

1. 创建类

C++中, 类通过class来实现. 在C语言中, 可以通过结构体模拟class来实现类的包装, 我们以实现一个不可变长的栈为例:

typedef struct {
    int* content;
    int top;
    int size;
} Stack;

此时Stack结构体中包含了栈相关的数据

关于类方法, 由于结构体中不能放置函数, 因此需另寻方法. 首先想到的是函数指针, 以pop为例:

void pop();

typedef struct{
	int *content;
	int top;
	int size;
	void (*pop)();
} Stack;

聪明的你应该发现了问题: pop() 函数的实现需要知道Stack中的contenttop数据, 而直接通过.调用函数指针时, 函数无法知道是哪个Stack类型的变量调用了他, 因此必须通过参数的方式告知函数是哪个Stack对象调用了他, 因此这里需要把方法写在结构体外面:

typedef struct{
	int *content;
	int top;
	int size;
} Stack; 
// Stack.pop()
void stack_pop(Stack *s);

这里在方法名前加上stack_防止命名冲突.

由于C语言中无法声明一个变量是private的还是public的, 因此就全靠自觉了()

补全Stack相关的操作:

```c
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

// class Stack

// private
typedef struct {
    int* content;
    int top;
    int size;
} Stack;

// public
Stack stack_init(int size);

void stack_quit(Stack* s);

bool stack_push(Stack* s, int target);

bool stack_pop(Stack* s);

int stack_top(const Stack* s);

void stack_is_empty(const Stack* s);

void stack_is_full(const Stack* s);

// class

此处传入的Stack变量为指针形式可以加快运行速度, 节省内存, 并使函数能够修改传入结构体的值.

在声明Stack类型对象后, 需调用stack_init函数来初始化对象; 在对象不需要再使用时, 需调用stack_quit函数来释放对象:

int main(){
	Stack *stack_1;
	stack_1 = stack_init(100);
	
	...

	stack_quit(stack_1);
}

Stack *stack_init(int size){
	Stack *s = (Stack *)malloc(sizeof(Stack));
	s -> content = (int *)malloc(sizeof(int) * size);
	s -> size = size;
	s -> top = 0;
	return s;
}

void stack_quit(Stack *s){
	free(s -> content);
	free(s);
}

相较于C++, 有一个方便之处: 传入参数名不需要保证和类中变量名相同了. 这使得类中变量的命名更加自由了.

继承

假设我们需要实现一个类, 能够实现栈的功能, 并记录每次更改的时间:

// class timer

// private
typedef struct{
	Stack *stack;
	time_t time;
} Timer;

// public
Timer timer_init(int size);

void timer_get_time(Timer *t);

void timer_quit(Timer *t);

// class

可以看到, Timer类内包含Stack类的对象. 如果想要使用Stack类的方法, 只需要用.取出Timer中的stack, 对其使用Stack类的方法. 例如timer_init就可以使用stack_init方法来初始化其中的Stack对象:

Timer timer_init(int size){
	Timer t; 
	t -> stack = (Stack *)malloc(sizeof(Stack));
	t -> stack = stack_init(size);
	t -> time = 0;
	return t;
}

void timer_quit(Timer *t){
	stack_quit(t -> stack);
	free(t -> stack);
	free(t);
}

也可以使用Stack中的其他类方法:

int main(){
	Timer *timer_1;
	timer_1 = timer_init(100);

	stack_push(timer_1.stack, 114514);
	timer_get_time(timer_1);

	return 0;
}

多态

考虑Stack的另一个子类:

// class
// private
typedef struct{
	Stack *stack;
	char *msg;
} Msger;

// class

如果想要实现一个函数, 能够打印出Msger中的msg和Timer中的time, 应该如何实现?

C语言中, 想要实现像这样的多态, 似乎只能通过声明多个函数:

void timer_print(Timer *t){
	printf("Time = %ud", t -> time);
}

void msger_print(Msger *m){
	printf("Message: %s", m -> msg);
}

只能算勉强实现了多态.

学生党的第一篇文章(), 想必有很多疏漏之处, 恳请不吝赐教

标签:int,void,timer,stack,OOP,使用,C语言,Stack,size
From: https://www.cnblogs.com/blog-lxx11451/p/18016297

相关文章

  • 第四章:熟练使用有棱有角的内存
    《程序是怎样跑起来的》这本书的第四章“熟练使用有棱有角的内存”为我揭开了内存神秘的面纱,让我对计算机内存有了更加深入的了解。读完这一章,我对内存的管理和使用有了全新的认识,也对编程过程中内存的重要性有了更加深刻的体会。首先,这一章详细介绍了内存的层次结构,包括寄存器、......
  • 07. Git客户端的使用
    一、Git客户端  我们可以从Git的官网下载客户端,网址如下:https://git-scm.com/downloads/guis/。这里,我们下载第一个GitHubDesktop即可。然后,我们双击图标安装即可。安装完成后,双击图标,打开客户端。  如果有GitHub账号,我们点击登录,然后后跳转到如下界面。  配置......
  • ThreadLocal使用
     Thread:Thread类中有两个变量threadLocals和inheritableThreadLocals,两者都是ThreadLocal.ThreadLocalMap类型,默认情况下为null,对应源码为1ThreadLocal.ThreadLocalMapthreadLocals=null;23ThreadLocal.ThreadLocalMapinheritableThreadLocals=null;ritabl......
  • JSON相关注解的使用
    1.@JsonInclude当使用json进行序列化时,往往会遇到某个实体对象的属性为null,可以使用如下类注解使得属性值为null的时候Java Bean不参与序列化可以作用在类上,也可以作用在字段上@JsonInclude(JsonInclude.Include.NON_NULL)     其他常量值包括:Include.Include.ALWAYS   ......
  • StringUtils使用与源码分析
    在apache的lang3包中有个StringUtils工具类,该工具类为开发中常用的字符串处理工具类 非空判断,isBlank和isEmpty这俩方法的形参都是charSequence字符序列。isEmpty判断这个字符序列是否为null,还有长度是否为0,如果是,则返回true,反之返回falseisBlank在isEmpty之上还有一个,如果长度......
  • 《程序是怎样跑起来的》第四章——熟练使用有棱有角的内存?
    关于这一章,是目前让我最感兴趣的一章,因为说到了内存,在编程过程中我经常遇到内存这类的问题,如堆、栈溢出,如何更好的使用内存,所以对内存格外想要了解。内存的实体实际上是一种名为内存IC的电子元件,有多种类型如:RAM,ROM等等。内存IC中有电源、控制信号、地址信号、数据信号。通过地址......
  • VS Code 使用 php cs fixer 扩展根据 psr 规范修复/格式化代码
    参考https://github.com/PHP-CS-Fixer/PHP-CS-Fixerhttps://www.cnblogs.com/huangtailang/p/6604124.html环境软件/系统版本说明WindowsWindows10专业版22H219045.4046phpphp-8.2.5-nts-Win32-vs16-x64vscode1.86.2phpcsfixerv0.3.11vs......
  • MyBatis-Plus--在xml中使用wrapper的方法
    原文网址:​​MyBatis-Plus--在xml中使用wrapper的方法_IT利刃出鞘的博客-CSDN博客​​简介本文介绍MyBatis-Plus如何在xml中使用wrapper。分享Java技术星球(自学精灵):​​https://learn.skyofit.com​​ServiceQueryWrapper<T>wrapper=newQueryWrapper<T>();wrapper.eq("......
  • 机器视觉-tensorBoard使用说明
    tensorboard功能Yolov8源码已经集成了很多个metrics监控系统,源码位置:ultralytics\utils\callbacks\,包括wandb、tensorboard、clearml等等.和其他系统相比,tensorboard功能较弱.yolov8自动集成tensorboard功能包括:查看学习率查看mAP/precision/recall指标......
  • 8小时速成golang(五)golang高阶 channel基本定义和使用
     1、定义channel变量channel是Go语言中的一个核心类型,可以把它看成管道。并发核心单元通过它就可以发送或者接收数据进行通讯,这在一定程度上又进一步降低了编程的难度。 channel是一个数据类型,主要用来解决go程的同步问题以及go程之间数据共享(数据传递)的问题。goroutin......