C语言:使用结构体和指针函数实现面向对象思想(OO编程)
原文:https://www.linuxidc.com/Linux/2016-12/138789.htm
有关:《C语言:过年回家 发现只有我没有对象》
一、基础研究
观察如下两个程序a.c和b.c:
A.c
#define screen ((char far*)0xb8000000)
typedef strct c
{
char chr;
char color;
void (*put)(struct c*, int,int ); }ch; void f(ch*, int, int);
int main(void)
{
int n;
ch a;
a.chr='c';
a.color = ;
a.put =f;
a.put(&a,,);
return;
}
void f(ch* p, int row, int col)
{
screen[(row-)*+(col-)*] = p->chr;
screen[(row-)*+(col-)*+] = p->color;
return;
}
B.c
#define screen ((char far*)0xb8000000)
typedef strct c
{
char chr;
char color;
void(*setch)(struct c*, char);
void(*setcolor)(struct c*, char);
void (*put)(struct c*, int,int );
}ch; void f(ch*, int, int);
void f1(ch*, int, int);
void f2(ch*, int, int);
int main(void)
{
int n;
ch a; a.put =f;
a.setch =f1;
a.setcolor =f2;
a.setch(&a,'c');
a.setcolor(&a,);
a.put(&a,,);
return;
}
void f(ch* p, int row, int col)
{
screen[(row-)*+(col-)*] = p->chr;
screen[(row-)*+(col-)*+] = p->color;
return;
} void f1(ch* p, char)
{
p->chr = a;
return;
}
这两个程序都是要实现在屏幕上第10行40列打印一个绿色的字符c:
这两个程序的数据组织方式是一样的,都是使用结构体,而且对共性和个性的分离的思路也是一样的,都是将共性封装在main函数里,将个性实现在子函数里。
但是a.c和b.c封装和分离的角度是不一样的:
a.c没有将字符和颜色的属性赋值分离出来,而只是将显示功能分离出来,
b.c将字符、颜色的赋值和显示功能都分离了出来,用三个子函数实现,并将相对应的函数指针封装到结构体里去。
面向对象程序设计的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成,也就是说我们要尽量把功能以子函数的形式实现。
所以在这里虽然a和b的设计思想是相同的,但是b.c的封装性要比a.c的封装性更好。
再来看下一个程序:
现在要在?处添加语句,使程序能够实现功能。
这里ch * a=new (ch);的功能应该与ch a;相同,即定义一个struct c型的结构体变量a。但是我们用ch a;是开辟了一个ch大小的空间并把它命名为a,而这里ch * a=?只是对一个指针进行了赋值,我们一般对指针赋值只是把一个地址给它,并没有开辟空间,但是我们要实现ch a;的功能,必须要在这一句里对该地址开辟空间。现在的问题就是:怎么在给指针赋值时开辟内存空间?
我们知道数组在定义时可以开辟空间,但是数组定义需要单独的一句,而这里需要直接作为右值使用,所以这里需要动态地开辟空间。我们最常用的动态内存分配方法就是使用malloc函数,这个函数有一个参数,是要开辟的空间字节数,在这里我们要开辟的空间大小是结构体a的大小,但是我们不知道结构体a的大小,所以我们要用sizeof得出它的大小。用malloc开辟空间后再将其转换成结构体指针赋给a,程序如下:
我们之前使用过宏定义,但是在程序中是宏名直接替换掉后面的东西的,而这里宏有参数x,所以它是带参宏定义,它的格式为:#define 宏名(形参表) 字符串。这里的x就是一个形参。所以我们要在使用时在宏名后面传入实参。
这里的宏名是new,学过java我们会发现java里初始化对象也是使用new,这里的new其实也是实现一个相似的功能。我们可以把结构体ch理解成一个类,用new对它进行实例化,这样就可以实现面向对象的程序设计思想。其实java里实例化对象也是开辟一个内存空间并给这个空间取一个名字即对象名。结构体为什么可以实现类的功能呢?我们知道,类里面可以定义变量、数组、函数,并进行一些操作如赋值、调用函数之类的,只是在java中类里面程序员不能定义和使用指针进行操作。而结构体里面也可以进行定义变量、数组、函数指针等的操作,所以如果我们要用c语言编写具有面向对象思想的程序,我们可以用结构体来实现类似“类”的功能,并用带参宏定义来实现实例化的功能,或者可以直接用malloc函数来实现实例化,只不过这样语句比较重复。
虽然我们可以在c语言里面用这种方法实现面向对象的程序设计,但是这样毕竟不如用java之类的比较适合面向对象的语言来写有面向对象思想的程序。因为java的类里可以进行赋值、调用函数等功能而c里的结构体不能。java取消了程序员使用指针的权限,因为如果在这种高度封装的语言里使用指针很可能造成很多错误。
从这里看,面向对象和面向过程程序设计思想的区别在哪里呢?面向对象的程序可能需要更多的封装,它的每一个对象都是为执行特定的功能而封装的,对象与对象之间相对比较独立,关系清晰,便于程序的功能细化、管理维护,但是也会造成程序的代码量增大。面向过程的程序封装的主要是一些数据结构,一个函数、变量可以被以多种角度来使用,这样使程序变得十分精简短小,但是不容易修改和补充。
我们写程序是用来解决问题的,而且要解决的是现实中的问题,所以我们需要将现实问题转化为符号化的问题,而现实中的问题是由个体所组成的,所以我们将数据和处理数据的方法封装起来形成一个个体,这个个体在问题里面有专门的功能,比如一张纸可以折叠,一支笔可以写,这样有助于我们以自身的角度进行思考分析,这就是面向对象。如果用面向过程的思路,会导致问题与程序之间的转化不好处理,可能使解决问题出现偏差。
二、扩展研究
1、动态开辟内存空间的函数有哪些?
答:c语言有三个函数可以动态开辟数组:malloc函数、calloc函数、realloc函数。
c语言提供了malloc函数和free函数用来执行动态内存分配和释放,这些函数维护一个可用内存池,malloc函数可以从内存池中提取一块合适的内存,free函数用来释放这块内存以供别的程序使用。Malloc函数分配的是一块连续的内存,返回值是一个指向被分配的内存块起始位置的指针。Malloc实际分配的内存可能比你请求的的多一点,也可能不会,这是由编译器决定的。但是malloc也可能分配失败,如果操作系统无法向malloc函数提供足够的可用内存,那么它会返回一个NULL指针。Malloc返回的指针类型为void *型。Free的参数必须要么是NULL,要么是malloc函数、calloc函数、realloc函数返回的值。
Calloc函数的参数是所需元素的数量和每个元素的字节数,而不是总的字节数。Calloc会把分配的内存都初始化为0,而malloc不会初始化。
Realloc函数用于修改一个原先已分配的内存块的大小,如果原先的内存块大小无法改变,那么realloc会分配另一块正确大小的内存,并把原先那块内存的内容复制到新的块上。如果realloc的第一个参数为NULL,那么它的作用和malloc一样。
三、研究总结
这一章里我们学习了动态分配内存的方法,以及怎么使用宏定义,其实它们都是为了更好地进行封装。为了对程序进行更好地封装,人们使用了各种方式,甚至开发了封装性更强的高级语言,这使我们解决专门问题的能力更强了。这样我们编程只是将共性实现为个性。因为语言只是工具,程序员应该更专注地研究算法而不是把时间花在语言上,所以现在的语言都是为了简化程序员的工作所造成的。
我们封装的过程,是对事物进行抽象的过程,也是对事物进行认识的过程,我们从开始到现在,封装的层次越来越深,处理的问题也越来越复杂。因为我们需要理清复杂问题的内部规律,从而找出解决问题的办法,而深层次的封装使问题恢复成本来的样子就是一种解决办法,当封装的程度达到了一定的水平,就是面向对象的程序设计思想。
C语言:使用结构体和指针函数实现面向对象思想(OO编程)的更多相关文章
- c语言里用结构体和指针函数实现面向对象思想
一.基础研究 观察如下两个程序a.c和b.c: A.c: B.c: 这两个程序都是要实现在屏幕上第10行40列打印一个绿色的字符c: 这两个程序的数据组织方式是一样的,都是使用结构体,而且对共性和个性 ...
- c语言,结构体里面的函数
以linux-3.2内核代码为例,结构体里面的函数的用法: 例,在某驱动文件中,定义了一个平台设备驱动: static struct platform_driver s3c24xx_led_drive ...
- c语言指向结构体的指针作为函数参数
注意 这里包括形参和实参 struct dangdangtest { ]; int num; }; void change(int num)//值传递 新建一个变量接受传递的值 { num = ; } ...
- C语言_结构体变量指针做函数参数的使用案例
# include <stdio.h> # include <stdlib.h> # include <string.h> # include <malloc ...
- C语言结构体中的函数指针
这篇文章简单的叙述一下函数指针在结构体中的应用,为后面的一系列文章打下基础 本文地址:http://www.cnblogs.com/archimedes/p/function-pointer-in ...
- c语言中较常见的由内存分配引起的错误_内存越界_内存未初始化_内存太小_结构体隐含指针
1.指针没有指向一块合法的内存 定义了指针变量,但是没有为指针分配内存,即指针没有指向一块合法的内浅显的例子就不举了,这里举几个比较隐蔽的例子. 1.1结构体成员指针未初始化 struct stude ...
- 将c语言的结构体定义变成对应的golang语言的结构体定义,并将golang语言结构体变量的指针传递给c语言,cast C struct to Go struct
https://groups.google.com/forum/#!topic/golang-nuts/JkvR4dQy9t4 https://golang.org/misc/cgo/gmp/gmp. ...
- C语言结构体和指针
指针也可以指向一个结构体,定义的形式一般为: struct 结构体名 *变量名; 下面是一个定义结构体指针的实例: struct stu{ char *name; //姓名 int num; //学号 ...
- go语言的结构体指针
Go 语言结构体 Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型. 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合. 结构体表示一项记录,比 ...
随机推荐
- 洛谷P1123取数游戏题解
题目 这是一道简单的搜索题,考查的还是比较基础的东西,其时搜索有时候并不难写,主要是要想到怎么搜.比如这个题,如果想二维四个方向搜则没有头绪,反之因为搜索是用递归实现的,所以我们可以使用递归的特性,把 ...
- web页面简单布局的修改,测试中的应用
在做功能测试的时候发现,界面显示不美观,觉得登录按钮应向上移动,那么如何移动呢? 很简单:使用开发者工具找到这个按钮所在的div,修改其中的属性值,top值减小,即可实现按钮向上移动,具体可以看效果
- python中可变参数和关键字参数总结
#_*_coding='utf-8' #可变参数 def person(name,age,*args): #定义了可变参数args print('传入的名字为:',name) print('传入的年龄 ...
- C Looooops POJ - 2115 (exgcd)
一个编译器之谜:我们被给了一段C++语言风格的循环 for(int i=A;i!=B;i+=C) 内容; 其中所有数都是k位二进制数,即所有数时膜2^k意义下的.我们的目标时球出 内容 被执行了多少次 ...
- HNOI2019
省选总结 day0 写了下平时不经常写的模板,像什么\(LCT\),圆方树,\(exlucas\)之类的,但是一个都没考. day1 提前十几分钟进了考场,可以提前动电脑,赶紧把\(vimrc\)打了 ...
- 多项式细节梳理&模板(多项式)
基础 很久以前的多项式总结 现在的码风又变了... FFT和NTT的板子 typedef complex<double> C; const double PI=acos(-1); void ...
- 洛谷SP22343 NORMA2 - Norma(分治,前缀和)
洛谷题目传送门 这题推式子恶心..... 考虑分治,每次统计跨过\(mid\)的所有区间的答案和.\(i\)从\(mid-1\)到\(l\)枚举,统计以\(i\)为左端点的所有区间. 我们先维护好\( ...
- HAOI2017 简要题解
「HAOI2017」新型城市化 题意 有一个 \(n\) 个点的无向图,其中只有 \(m\) 对点之间没有连边,保证这张图可以被分为至多两个团. 对于 \(m\) 对未连边的点对,判断有哪些点对满足将 ...
- bit、Byte、bps、Bps、pps、Gbps的单位详细说明及换算
1. bit 电脑记忆体中最小的单位,在二进位电脑系统中,每1bit 可以代表0 或 1 的数位讯号. 2. Byte 字节单位,一般表示存储介质大小的单位,一个B(常用大写的B来表示Byte)可代表 ...
- 利用saltstack批量安装clamav杀毒软件
源码包安装: clamav_source: file.managed: - name: /tmp/clamav-0.99.2.tar.gz - unless: test -f /tmp/clamav- ...