在C语言中使用OOP

打印 上一主题 下一主题

主题 873|帖子 873|积分 2619

前言

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

1. 创建类

C++中, 类通过class来实现. 在C语言中, 可以通过结构体模拟class来实现类的包装, 我们以实现一个不可变长的栈为例:
  1. typedef struct {
  2.     int* content;
  3.     int top;
  4.     int size;
  5. } Stack;
复制代码
此时Stack结构体中包含了栈相关的数据
关于类方法, 由于结构体中不能放置函数, 因此需另寻方法. 首先想到的是函数指针, 以pop为例:
  1. void pop();
  2. typedef struct{
  3.         int *content;
  4.         int top;
  5.         int size;
  6.         void (*pop)();
  7. } Stack;
复制代码
聪明的你应该发现了问题: pop() 函数的实现需要知道Stack中的content及top数据, 而直接通过.调用函数指针时, 函数无法知道是哪个Stack类型的变量调用了他, 因此必须通过参数的方式告知函数是哪个Stack对象调用了他, 因此这里需要把方法写在结构体外面:
  1. typedef struct{
  2.         int *content;
  3.         int top;
  4.         int size;
  5. } Stack;
  6. // Stack.pop()
  7. void stack_pop(Stack *s);
复制代码
这里在方法名前加上stack_防止命名冲突.
由于C语言中无法声明一个变量是private的还是public的, 因此就全靠自觉了()
补全Stack相关的操作:
  1. ```c#include #include #include // class Stack// privatetypedef struct {
  2.     int* content;
  3.     int top;
  4.     int size;
  5. } Stack;// publicStack 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函数来释放对象:
  1. int main(){
  2.         Stack *stack_1;
  3.         stack_1 = stack_init(100);
  4.        
  5.         ...
  6.         stack_quit(stack_1);
  7. }
  8. Stack *stack_init(int size){
  9.         Stack *s = (Stack *)malloc(sizeof(Stack));
  10.         s -> content = (int *)malloc(sizeof(int) * size);
  11.         s -> size = size;
  12.         s -> top = 0;
  13.         return s;
  14. }
  15. void stack_quit(Stack *s){
  16.         free(s -> content);
  17.         free(s);
  18. }
复制代码
相较于C++, 有一个方便之处: 传入参数名不需要保证和类中变量名相同了. 这使得类中变量的命名更加自由了.
继承

假设我们需要实现一个类, 能够实现栈的功能, 并记录每次更改的时间:
  1. // class timer
  2. // private
  3. typedef struct{
  4.         Stack *stack;
  5.         time_t time;
  6. } Timer;
  7. // public
  8. Timer timer_init(int size);
  9. void timer_get_time(Timer *t);
  10. void timer_quit(Timer *t);
  11. // class
复制代码
可以看到, Timer类内包含Stack类的对象. 如果想要使用Stack类的方法, 只需要用.取出Timer中的stack, 对其使用Stack类的方法. 例如timer_init就可以使用stack_init方法来初始化其中的Stack对象:
  1. Timer timer_init(int size){
  2.         Timer t;
  3.         t -> stack = (Stack *)malloc(sizeof(Stack));
  4.         t -> stack = stack_init(size);
  5.         t -> time = 0;
  6.         return t;
  7. }
  8. void timer_quit(Timer *t){
  9.         stack_quit(t -> stack);
  10.         free(t -> stack);
  11.         free(t);
  12. }
复制代码
也可以使用Stack中的其他类方法:
  1. int main(){
  2.         Timer *timer_1;
  3.         timer_1 = timer_init(100);
  4.         stack_push(timer_1.stack, 114514);
  5.         timer_get_time(timer_1);
  6.         return 0;
  7. }
复制代码
多态

考虑Stack的另一个子类:
  1. // class
  2. // private
  3. typedef struct{
  4.         Stack *stack;
  5.         char *msg;
  6. } Msger;
  7. // class
复制代码
如果想要实现一个函数, 能够打印出Msger中的msg和Timer中的time, 应该如何实现?
C语言中, 想要实现像这样的多态, 似乎只能通过声明多个函数:
  1. void timer_print(Timer *t){
  2.         printf("Time = %ud", t -> time);
  3. }
  4. void msger_print(Msger *m){
  5.         printf("Message: %s", m -> msg);
  6. }
复制代码
只能算勉强实现了多态.
学生党的第一篇文章(), 想必有很多疏漏之处, 恳请不吝赐教

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

罪恶克星

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表