网页资讯视频图片知道文库贴吧地图采购
进入贴吧全吧搜索

 
 
 
日一二三四五六
       
       
       
       
       
       

签到排名:今日本吧第个签到,

本吧因你更精彩,明天继续来努力!

本吧签到人数:0

一键签到
成为超级会员,使用一键签到
一键签到
本月漏签0次!
0
成为超级会员,赠送8张补签卡
如何使用?
点击日历上漏签日期,即可进行补签。
连续签到:天  累计签到:天
0
超级会员单次开通12个月以上,赠送连续签到卡3张
使用连续签到卡
07月25日漏签0天
c语言吧 关注:798,853贴子:4,357,534
  • 看贴

  • 图片

  • 吧主推荐

  • 视频

  • 游戏

  • 首页 上一页 1 2 3 4 下一页 尾页
  • 57回复贴,共4页
  • ,跳到 页  
<<返回c语言吧
>0< 加载中...

回复:听说C语言也可以面向对象,就让我们一起愉快地实现它吧

  • 只看楼主
  • 收藏

  • 回复
  • 莫回头day
  • 麻婆豆腐
    11
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
[cp]生命中再无聊的时光都是限量版,请好好珍惜[心][心][心]~~早安[/cp]


  • 暗丶梦魇丶陨灭
  • 帕秋莉糕
    12
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
抽点空把这个帖子搞完
==================================
前面说到了oop的本质,现在我们考虑用C语言来实现。
再来想想之前所设计的,用struct进行封装。假设有struct A和struct B,我要用A作为B的父类,应该这么考虑呢?很简单,通过B可以找到A。你可能回想直接在B里面插入struct A即可,但是这样的话每次声明一个struct B变量都会对应产生一个A变量,这样会导致对A类型的复制。我们说了,oop一个重要目的是实现代码的重用,如果我声明了两个struct B变量,它们之间就会产生两个struct A变量(嵌套在struct B结构体中),这样可不是重用。因此最好的办法是使用指针。但是,struct A只是个定义,本身没有地址,指针应该指向哪里呢?
现在我们再来思考一下oop的本质,A作为B的父类,意义在于B可以在A里面找到对应的属性,可见类A是什么东西并不重要,类A并不一定非要是个抽象定义,假如它本身就是一段数据(即在内存中占据一段空间),那么我们就可以在里面搜索了(就像函数一样),因此我们考虑声明struct A后,立即定义struct A classA;将classA看作类A,同时声明struct B classB;将classB看作类B,这样就可以在classB中插入classA的指针,通过这个指针找到classA中的属性。
但这样还是有问题,例如,我希望找到classB.k,但是k在classA中,很明显是无法调用的,你可能需要写个类似classB.pA->k的结构来找到k,但这样写就失去了继承的意义,或者说根本不是继承。由此可见,想用struct模拟出类来基本上是不现实的,我们应该使用其他方法来实现。


2025-07-25 01:46:12
广告
不感兴趣
开通SVIP免广告
  • 暗丶梦魇丶陨灭
  • 帕秋莉糕
    12
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
假设我已经将一系列的数据和函数放在了一起,并构成了两个类,那么应该怎样让类B自动搜索类A的内容呢?既然编译器不能帮助我们,那我们貌似就只能想其他办法了,也许你马上就能想到,写一个函数来实现。没错,函数能够帮助我们完成任务。
例如,我现在创建一个GetValue函数,我希望输入属性的名称后可以返回属性的值。现在的第一个问题,属性的名字应该怎么传递。在C语言中,虽然你可以给变量取个名字,但这个名字是给程序员看的,编译器会将其转化成地址,因此,变量名是不可能传递的。这意味着简单地用struct将属性和方法封装起来不可行,因为即使你写了函数,函数也无法根据变量名判断struct内部和你传入的变量名字相同的值,因为对于编译器而言,它们都没名字,只是地址而已。这也是struct无法实现封装的重要因素。所以,对于每个值,我们都应该给其取个名字,即属性名,这里我考虑用字符串来做属性名。


  • 暗丶梦魇丶陨灭
  • 帕秋莉糕
    12
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
如果我给一个数据起了个名字,那很明显,名字应该和数据是一一对应的。一个类会有很多属性,也就意味着有很多属性名和属性值,为了互相不混乱,我们需要用一定的数据结构来管理它们。在这里,我考虑使用字典来实现。所谓字典,就是一系列的数据对,每一对数据都由“键”(key)和“值”(value)组成,其中,一个字典里每一个键都是唯一的,通过键就可以找到值。例如, "a":10, "b":"hello", "c":1.3, "d":10 这几个数据组成的数据对构成一个字典,"a"对应着10,”b“对应着"hello",这样一系列的数据组合在一起就是字典。我们可以用struct将一对键和值包在一起,实现键和值的打包。至于字典的组成,我这里使用简单灵活好用的单链表实现。


  • 暗丶梦魇丶陨灭
  • 帕秋莉糕
    12
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
首先是构成一对键-值对:


  • 暗丶梦魇丶陨灭
  • 帕秋莉糕
    12
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
我们利用字典结构保存了所有属性(包括方法),调用的时候查询字典即可。由于这里的字典是用单链表实现的,所以创建字典就是创建单链表。另外,可能我前面说得有点混乱,这里再提一下,字典里保存了所有属性,搜索属性就是搜索单链表,这里的单链表实际就是我们创建的类。也就是说,创建类的过程就是创建单链表的过程,子类就是下一个单链表(其中包含了父类,即另一个单链表的地址)。这样一来就清楚了,我们需要创建一个单链表,这里我在链表最尾部的一节存放父类的地址(因为只有搜索到了尾部都没有找到属性才需要在父类中搜索)。创建类(即单链表)的代码如下:

其中,GreateClass函数的参数就是父类(另一个链表)的地址。这里我定义了两个特殊的属性名,一个是parent,一个是noparent,这是为了解决没有父类的情况(传递参数为NULL)。同时这里没有考虑多继承。


  • 暗丶梦魇丶陨灭
  • 帕秋莉糕
    12
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
通过调用GreateClass函数,将返回一个链表的指针,这个链表目前只有一节,即父类的地址。仅仅这个是不够的,所以我需要给类添加属性的方法。



  • 暗丶梦魇丶陨灭
  • 帕秋莉糕
    12
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
添加属性就是在链表中插入值,上面FindAttributeInInstance函数的作用是在当前链表里查找属性是否存在,而不会在上一级链表(即父类)中查找。为什么呢?这里就涉及类属性和实例属性了。类属性是指类本身具有的属性,所以依据该类创建的实例共享该属性。假如其中一个实例修改了该类的值,那么其他实例读取该值时也是变化之后的。而实例属性则是每个实例各自的,互相不影响。其实你应该可以看出,我们这里的类本质上是实例化了的,如果想定义一个实例,那么它将和类没有本质的区别,都是一个链表(请注意,只有我这里代码是这样,请不要在其他语言推而广之)。如果你这里传入的是实例,那它就给实例添加属性;如果你传入的是某个类,那就给该类添加属性。
FindAttributeInInstance函数如下:


2025-07-25 01:40:12
广告
不感兴趣
开通SVIP免广告
  • 暗丶梦魇丶陨灭
  • 帕秋莉糕
    12
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
很多时候,我们也需要知道某个属性在整个结构中是否存在(包括父类中),所以需要如下函数:


  • 暗丶梦魇丶陨灭
  • 帕秋莉糕
    12
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
有了上面的步骤,基本上主要框架就搭好了,不过貌似我们还需要一个根据属性获取值的方法:


  • 暗丶梦魇丶陨灭
  • 帕秋莉糕
    12
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
当程序运行结束后,不要忘了释放内存,这毕竟是C语言


  • 暗丶梦魇丶陨灭
  • 帕秋莉糕
    12
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
前面我提到,属性分为实例属性和类属性,类属性可以单独开一个文件来定义、添加,但实例属性往往是在类里面完成添加的。因此,申请实例就不适合使用GreateClass来创建了,因为它申请好了之后还需要自己去给它添加属性,我们希望的是实例一申请成功就自动完成实例属性的创建和添加。这里我们需要用到构造函数。所谓构造函数,就是一个实例申请时自动调用的函数,它是类的一部分,作为类的方法存在。现在我假设构造函数默认的名字是Init,申请实例的代码如下:


  • 暗丶梦魇丶陨灭
  • 帕秋莉糕
    12
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
在构造函数中,你可以完成实例属性的创建、初始化,或者其他一些初始化的工作。注意构造函数至少有一个参数就是实例本身,其他语言有时候会省略这个参数,由编译器传递,但这里编译器不会帮助我们,所以得我们自己完成。
上面56行代码出现一点问题,因为没有测试过,所以刚才才看到。上面的Init没有返回值,实际上是应该有的,因为我们这里的链表地址并非恒定不动(因为是在前面添加属性),所以如果Init中添加了属性应该把新的地址返回。
修改后代码如下:


  • 暗丶梦魇丶陨灭
  • 帕秋莉糕
    12
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
基本框架就这样搭好了。现在你能够创建类,创建实例,并通过属性找到值,能够动态添加属性,完成后释放内存。但是,我的代码还不够完整,比如没有删除属性的代码,比如没有细致的错误处理(特别是内存的释放要特别小心),如果你有兴趣,你可以让它更完善。整个流程就是这样。下面我贴上简单的不完全测试代码。


2025-07-25 01:34:12
广告
不感兴趣
开通SVIP免广告
  • 暗丶梦魇丶陨灭
  • 帕秋莉糕
    12
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼


登录百度账号

扫二维码下载贴吧客户端

下载贴吧APP
看高清直播、视频!
  • 贴吧页面意见反馈
  • 违规贴吧举报反馈通道
  • 贴吧违规信息处理公示
  • 首页 上一页 1 2 3 4 下一页 尾页
  • 57回复贴,共4页
  • ,跳到 页  
<<返回c语言吧
分享到:
©2025 Baidu贴吧协议|隐私政策|吧主制度|意见反馈|网络谣言警示