免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4062 | 回复: 12
打印 上一主题 下一主题

我对C与OO的理解 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-07-20 22:04 |只看该作者 |倒序浏览
本帖最后由 mtloveft 于 2010-07-20 22:06 编辑

提示:本文是介绍C是如何实现OO!
blog:               http://oldtown.cublog.cn/
URL:                http://blog.chinaunix.net/u3/114767/showart_2277244.html

OO的基础就是abstractionencapsulationpolymorphism inheritance
也就是抽象,封装,多态,继承
OOD的基础就是
Encapsulate what varies.
Favor composition over inheritance
Program to interfaces, not implementations.

封装变化的部分,组合优于继承,对接口编程,而不是实现。

有了这些基本概念,看看高级语言的实现。图如下:


Man Woman 都继承Person,把一些共同的属性封装到了Parent类里,这体现了Encapsulation
和Inheritance。对于do()方法是抽象方法,所以子类必须去实现,这样在实际的代码中就
可以利用多态了,例如Persion p = getPersion(flag); p.do(if)这样只有在执行期间才能判断
p的类型,有了OO这些基础,在来看看C怎么实现呢?其实实现也很简单,但是要熟练
运用就看你对OO的掌握程度了。

实例代码如下
  1. Persion p = getPersion(flag);
  2. p.getName();
  3. p.do(if);

  4. Man m = (Man) p;
  5. Persion p2 = (Persion) m;
复制代码
C虽然没有OO的概念,但是如果想写出易扩展,易维护的source code,你就必须掌握C的隐性OO概念。
看看C的结构图:

代码如下
  1. Persion* p = getPersion(flag);
  2. p->opt->getName();
  3. p->opt->do((void*)&if);

  4. Struct Man * m = (Struct Man *) p;
  5. Struct Persion * p2 = (Struct Persion *) m;
复制代码
看看代码是不是很像啊,除了操作符不同之外,基本都一样。看到C的OO实现了吧。

其实C也有继承的,你如果了解OO语言的继承是怎么实现的,那就会知道C怎么
实现了,OO语言继承的数据放置位置,首先放父类的数据,然后放自己的数据。
图如下:


比如实例GTT : Persion的数据layout如下:


这样在C就很容易实现了。定义两个struct,把一个struct的定义放到另外一个struct的定义最前头,
这样就是OO的继承的实现了,可以互相转换类型,如果把一个struct放到另一个struct的其他
位置,就可以理解为包含了,也就是composition, has-A关系。
OO设计不难,但你要掌握它的精髓,他要达到什么效果,
精髓就是flexable,maintainable,resuable这3个单词。即柔软,可维护,可重用。这样设计的工程中时刻考虑这些,必然会设计出greate
software了,当我看到linux的实现时,感到写linux这些人太他妈的有才了。


在以上的代码中,如果把取得p的过程放到另外的一个类里,就可以理解为是一个factory design pattern了。把一些变化的方法抽象到另外的一个类里,是不是跟bridge design pattern 很象呢,
本没路,走的人多了就有路了。design pattern 本没有,只是你用的多了,就掌握精髓了。
那么多design pattern,背是没有的,要去运用,运用之后去总结,必然收获很大。

论坛徽章:
0
2 [报告]
发表于 2010-07-20 23:24 |只看该作者
C还没太用过面向对象,还是模块化的开发

论坛徽章:
0
3 [报告]
发表于 2010-07-20 23:26 |只看该作者
可能是开发思路吧,如果开始就用OO思想去做,估计用C会很累。。。

论坛徽章:
0
4 [报告]
发表于 2010-07-21 20:01 |只看该作者
C还没太用过面向对象,还是模块化的开发
linux初学三月 发表于 2010-07-20 23:24

不是没太用过,是用的太多了。KernelCode基本各个地方都在利用OO思想。

论坛徽章:
0
5 [报告]
发表于 2010-07-21 20:02 |只看该作者
可能是开发思路吧,如果开始就用OO思想去做,估计用C会很累。。。
kgn28 发表于 2010-07-20 23:26


就是开始就用OO思想去做,才能做的强大,所以Kernel的扩展性才做的那么好。

论坛徽章:
0
6 [报告]
发表于 2010-07-22 05:41 |只看该作者
不错.

论坛徽章:
0
7 [报告]
发表于 2010-07-22 11:09 |只看该作者
KernelCode用的思想是OO的,看起来还是有点困难

论坛徽章:
0
8 [报告]
发表于 2010-07-22 17:01 |只看该作者
楼主说的挺有道理的,比如内核中邻居子系统的实现,就是定义了邻居层,然后针对邻居层提供的数据结构和 虚函数,分别实现了ipv4的arp协议和ipv6的邻居发现协议。

论坛徽章:
0
9 [报告]
发表于 2010-07-26 21:42 |只看该作者
回复 1# mtloveft
高级语言的多层继承如下图

也就是男学生要继承于男人,男人又继承于人,数据的构成如下

如果用C怎么实现呢?其实是很简单的。定义代码如下
  1. struct Person {
  2.     char* name;
  3.     int      性别;
  4. }

  5. struct Man {
  6.     strcut Person p;
  7.     char* beard;
  8. }

  9. struct Student {
  10.     struct Man m;
  11.     int id;
  12. }
复制代码
操作代码如下
  1. Person *p;
  2. Man *m;
  3. Student *s;
  4. p = kzalloc(sizeof(struct Student), GFP_KERNEL);
  5. m = (Man *) p;
  6. s = (Student *) p;

  7. p = (Person *) m;
  8. p = (Person *) s;

  9. m = (Man *) s;
  10. s = (Student *) m;
复制代码
当然给p分配内存大小就必须使Student的大小了,这样就不用考虑内存越界的问题了。
其实高级语言也是这么实现的。你看看构造方法里是不是第一条语句就是构造基类。其它语句是编译不过去的。
这种多层继承在Linux内核程序里很多地方都有,例如socket的实现。
看看图,如下


结构够复杂的了吧,没办法,要利用高级语言的特性,只能这么用了。
这样udp_sock, inet_sock inet, sock sk之间就可以互相转换了。而不用考虑越界的问题了。
当然最开始的内存分配也应该如下
  1. Sock * sk = kzalloc(sizeof(struct udp_sock), GFP_KERNEL);
复制代码
这样才能保证数据的正确性。

文章地址

http://blog.chinaunix.net/u3/114767/showart_2282422.html

论坛徽章:
0
10 [报告]
发表于 2010-07-27 15:32 |只看该作者
最近看了些内核代码,诚然如楼主所说,利用结构体内存布局,来实现继承。

内核里还有一种方法,container_of宏,可以由父类对象指针得到子类对象指针来操作,用于多态实现。

例如:
struct persion_operations {
      int (*do_a)(struct persion *persion);
};
struct persion {
     struct persion_options *ops; /* 人的操作函数 */
};

struct man {
     struct persion base;
};

struct man man;
struct persion_operations  man_ops = {
     .do_a = man_do_a;
}
persion_init(&man.base, &ops);

int man_do_a(struct persion *persion)
{
      struct man *man = container_of(persion, struct man, base);
}

同理可以实现woman的do_a操作,设置是student的do_a操作。
而对外,persion只需要同样的do_a操作接口。

container_of很强大!而且不用关心内存布局。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP