软件设计本质论(Essential Design) —白话面向对象 (转注:关于c语言实现封装继承多态的一堆博文)

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

软件设计本质论(Essential Design) —白话面向对象

分类: 23.设计本质论系列 2006-08-15 21:42 4361人阅读 评论(11) 收藏 举报

软件设计本质论(Essential Design)白话面向对象

 

转载时请注明出处:http://blog.csdn.net/absurd/

 

不同的人在谈面向对象编程(OOP)时所指的含义并不相同。有人认为任何采用图形界面的应用程序都是面向对象的。有人把它作为术语来描述一种特别的进程间通信机制。还有人使用这个词汇是另有深义的,他们其实是想说:“来啊,买我的产品吧!”我一般不提OOP,但只要提到,我的意思是指使用继承和动态绑定的编程方式。 --C++沉思录》

 

C++沉思录》说的是十几年前的事了,现在大家对面向对象的回答已经是众口一词:封装、继承和多态。大家都知道,在面向对象中,一辆汽车是一个对象,汽车这个概念是一个类。汽车有漂亮的外观,把各种内部原理都隐藏起来了,司机不必知道它的内部工作原理仍然能开车,即使汽车随技术的进步不断升级,对司机也没有什么影响,这就是封装的好处。

 

汽车是交通工具的一种,汽车是一个类,交通工具也是一个类,而交通工具类包括了汽车类,从而具有更广泛的意义。这种从抽象到具体的关系就是继承关系,我们可以说汽车类继承了交通工具类,汽车类是交通工具类的子类,交通工具类是汽车类的父类。

 

作为交通工具,它肯定可以运动(move),从甲地运动到乙地,就起到了交通的作用。轮船是一种交通工具,所以轮船类也是交通工具类的子类。同样是运动,轮船的运动和汽车的运动方式肯定有所不同,这样以不同的方式完成同样的功能就叫多态

 

关于对象:对象就是某一具体的事物,比如一个苹果,一台电脑都是一个对象。每个对象都是唯一的,两个苹果,无论它们的外观有多么相像,内部成分有多么相似,两个苹果毕竟是两个苹果,它们是两个不同的对象。对象可以是一个实物,也可能是一个概念,比如某个苹果对象是实物,而一项政策可能就是一个概念性的对象了。

 

关于类:对象可能是一个无穷的集合,用枚举的方式来表示对象集合不太现实。抽象出对象的特征和功能,按此标准将对象分类,这就引入类的概念。类就是一类事物的统称,类实际上就是一个分类的标准,符合这个分类标准的对象都属于这个类。当然,为了方便起见,通常只需要抽取那些,对当前应用来说是有用的特征和功能。

 

关于抽象类:类是对对象的抽象,比如,苹果是对所有具体的苹果的抽象。如果我们对苹果这个类进行一步抽象,可以得到一个水果类。这种对类本身进行抽象而得到的类,就是抽象类。抽象类不像普通类,它是没有对象与之对应的。像苹果类,你总是可以拿到一个叫苹果的东西,而对于水果类,根本没一个真正叫水果的东西。你可以说一个苹果是一个水果,从逻辑上讲没有错,但没有什么意义。一般在程序中,抽象类是不能实例化的。

 

关于面向对象:面向对象就是以对象为中心。为什么不说是面对类,而说是面向对象呢?类是对象的集合,考虑类实际上也是在考虑对象,有时甚至并不严格的区分它们。所以说面向对象一词比面向类更确切。

 

既然以对象为中心,面向对象所考虑的内容自然是对象、对象间的协作、对象的分类、类之间的关系等等,由此引申了出几个重要的概念。

 

1.        封装

what:对象也有隐私,对象的隐私就是对象内部的实现细节。要想对象保持良好的形象就要保护好对象隐私,所谓的封装其实就是保护对象隐私。当然,没有人能完全隐藏自己的隐私,比如你去转户口时,你不得不透露自己的家庭信息和健康状况。另外,在不同的场合所透露隐私的数量也不一样,朋友和家人可能会知道你更多隐私,同事次之,其他人则知道得更少。面向对象也考虑了这些实际的情况,所以像C++之类的语言有public/private/protected/friend等关键字,以适应于不同的情况。

 

why:封装可以隔离变化。据以往的经验,我们知道内部实现是容易变化的,比如电脑在不断的升级,机箱还是方的,但里面装的CPU和内存已是今非昔比了。变化是不可避免的,但变化所影响的范围是可以控制的,不管CPU怎么变,它不应该影响用户使用的方式。封装是隔离变化的好办法,用机箱把CPU和内存等等封装起来,对外只提供一些标准的接口,如USB插口、网线插口和显示器插口等等,只要这些接口不变,内部怎么变,也不会影响用户的使用方式。

 

封装可以提高易用性。封装后只暴露最少的信息给用户,对外接口清晰,使用更方便,更具用户友好性。试想,如果普通用户都要知道机箱内部各种芯片和跳线,那是多么恐怖的事情,到现在为止我甚至还搞不清楚硬盘的跳线设置,幸好我没有必要知道。

 

how:在C语言中,可以用结构+函数来模拟类的实现,而用这种结构定义的变量就是对象。封装有两层含义,其一是隐藏内部行为,即隐藏内部函数,调用者只能看到对外提供的公共函数。其二是隐藏内部信息,即隐藏内部数据成员。现在都建议不要对外公开任何数据成员,即使外部需要知道的数据成员,也只能通过函数获取。

 

C语言中要隐藏内部函数很简单:不要它把放在头文件中,在C文件中定义时,前面加static关键字,每个类放在独立的文件中。这样可以把函数的作用范围限于当前文件内,当前文件只有类本身的实现,即只有当前的类自己才能看到这些函数,这就达到了隐藏的目的。

 

C语言中要隐藏数据成员较为麻烦,它没有提供像C++中所拥有的public/protected/friend/private类似的关键字。只能通过一些特殊方法模拟部分效果,我常用的方法有两种。

 

其一是利用C的特殊语法,在头文件中提前声明结构,在C文件才真正定义它。这样可以把结构的全部数据信息都隐藏起来。因为外部不知道对象所占内存的大小,所以不能静态的创建该类的对象,只能调用类提供的创建函数才能创建。这种方法的缺陷是不支持继承,因为子类中得不到任何关于父类的信息。如:

头文件:

struct_LrcPool;

typedefstruct_LrcPoolLrcPool;

 

LrcPool*lrc_pool_new(size_tunit_size,size_tn_prealloc_units);

void*   lrc_pool_alloc(LrcPool*thiz);

void    lrc_pool_free(LrcPool*thiz, void*p);

void    lrc_pool_destroy(LrcPool*thiz);

 

C文件:

struct_LrcPool

{

   size_tunit_size;

   size_tn_prealloc_units;

};

 

LrcPool*lrc_pool_new(size_tunit_size,size_tn_prealloc_units)

{

   LrcPool* thiz = LRC_ALLOC(LrcPool, 1);

       

   if(thiz !=NULL)

   {  

       thiz->unit_size =unit_size;

       thiz->n_prealloc_units =n_prealloc_units;

   }

   

   returnthiz;

}

 

其二是把私有数据信息放在一个不透明的priv变量中。只有类的实现代码才知道priv的真正定义。如:

头文件:

struct_LrcBuilder

{

   LrcBuilderBegin     on_begin;

   LrcBuilderOnIDTag   on_id_tag;

   LrcBuilderOnTimeTag on_time_tag;

   LrcBuilderOnLrc     on_lrc;

   LrcBuilderEnd       on_end;

   LrcBuilderDestroy   destroy;

 

   charpriv[1];

};

 

 

C文件:

struct_LrcDumpBuilder

{

   FILE* fp;

};

 

typedefstruct_LrcDumpBuilderLrcDumpBuilder;

LrcBuilder*lrc_dump_builder_new(FILE*fp)

{

   LrcDumpBuilder* dataNULL;

   LrcBuilder* thiz = (LrcBuilder*)calloc(sizeof(LrcBuilder) +sizeof(LrcDumpBuilder), 1);

 

   if(thiz !=NULL)

   {

       thiz->on_begin    = lrc_dump_builder_on_begin;

       thiz->on_id_tag   = lrc_dump_builder_on_id_tag;

       thiz->on_time_tag = lrc_dump_builder_on_time_tag;

       thiz->on_lrc      = lrc_dump_builder_on_lrc;

       thiz->on_end      = lrc_dump_builder_on_end;

       thiz->destroy     = lrc_dump_builder_destroy;

       data = (LrcDumpBuilder*)thiz->priv;

       data->fp =fp != NULL ?fp : stdout;

   }

 

   returnthiz;

}

 

2.         继承

what: 继承描述的是一种抽象到具体的关系。具体的东西继承了抽象的东西的特性,比如说,水果这个概念比苹果这个概念更抽象,其意义更具有一般性,而苹果这个概念则更具体,其意义更狭窄一些,在面向对象里,我们可以说苹果类继承了水果类。继承是指继承了父类的特性,继承本质是源于分类学,细的分类继承大分类的特性。

 

why: 继承描述了抽象到具体的关系,所以能够有效利用抽象这件武器来战胜软件的复杂性。抽象在实现中无处不在,类就是对事物的抽象,提到苹果你就想到苹果这一类事物,无需要关心其大小、颜色和成分,苹果这两个字就足够了。名不正则言不顺,言不顺则事不成,看来老夫子已经领悟到了抽象的威力。

 

继承不但利用了抽象的力量来降低系统的复杂性,它还提供了一种重用的方式。假设我们承认下列面这个继承关系,苹果继承了水果,水果继承了食物,如果我们已经知道什么是食物,什么是水果,在描述苹果时,没有必要去重复讲解食物和水果的概念了,这就是重用,重用了对水果和食物两个概念的理解。

 

how: C语言中实现继承很简单,可以用结构来模拟。这种实现基于一个明显的事实,结构在内存中的布局与结构的声明具有一致的顺序。我们知道在程序描述事物的特征时,主要通过数据变量描述事物的属性特征,如颜色、重量和体积等,用函数来描述事物的行为特征,和运动、成长和搏斗等。在C语言中实现继承的方式如:

struct _GObject

{

 GTypeInstance  g_type_instance;

 volatile guint ref_count;

 GData         *qdata;

};

 

struct_GtkObject

{

 GObject parent_instance;

 guint32 flags;

};

 

struct_GtkWidget

{

 GtkObject parent_instance;

 guint16 private_flags;

 guint8 state;

 guint8 saved_state;

 gchar *name;

 GtkStyle *style;

 GtkRequisition requisition;

 GtkAllocation allocation;

 GdkWindow *window;

 GtkWidget *parent;

};

 

 

(GtkWidget继承GtkObjectGtkObject继承GObject)

      

继承在现实世界中应用很广,在程序里也是一样,甚至可以说是过度使用了。多年以前一些大师已经提出,优先使用组合而不是继承。主要原因有三点,首先是多级继承和多重继承太复杂了,失去了抽象带来的简洁性。其次是父类与子类之间共享太多信息,它们的耦合太紧密。三是父类与子类之间的关系在编译时就静态绑定了,很难做到在运行时多态。

 

现在一般都提倡,只继承接口不继承实现,通过组合达到代码重用的目的。在《设计模式》中是这样强调的,在MSCOM里也是这样做的。所以我基本上只使用接口继承,很少遇到什么麻烦,建议大家也遵循这一准则。

 

3.         多态

what: 尽管多态这个词本身就表明了它所代表的意义,但还是让初学者感到多少有些神秘。多态就是完成相同功能的多种方式,比如拿动物的运动来说吧,鸟的运动通常是飞,鱼的运动通常是游,陆上动物的运动通常是跑,同是运动,但方式不一样,这就是多态。不少人对多态的回答是,允许同名函数存在。这种回答显然没有抓住多态的本质。

 

why: 关于动物运动这个例子,可能无法展示多态的好处。我们来考虑另外一个多态的例子,U盘。U盘的技术含量可能不是很高,有很多厂家都在设计和生产,就是说U盘有多种不同的实现,这就是U盘的多态。U盘的多态性对消费者来说是有好处的,选择多了,你可以在价格、质量和外观等方式做出平衡,选择你中意的U盘。多态的前提是接口的一致性,否则多态造成的麻烦远胜于它带来的好处。不管U盘的体积、颜色和质量如何,它都必需遵循相应的USB标准,这些U盘在任何带USB接口的电脑上都可以使用。

 

how: 多态在C语言中通常用函数指针来实现,函数指针定义了函数的原型,即它的参数和返回值的描述,以及函数的意义,不同的函数可以有相同的函数原型,比如排序函数,无论是快速排序还是归并排序,它们的实现不一样,但函数原型可以一样。在不同的情况下,让函数指针到不同的函数实现上,这就实现了多态。下面的C语言例子:

 

       接口:

struct_LrcBuilder;

typedefstruct_LrcBuilderLrcBuilder;

 

typedef LRC_RESULT (*LrcBuilderBegin)(LrcBuilder*thiz, constchar*buffer);

typedef LRC_RESULT (*LrcBuilderOnIDTag)(LrcBuilder*thiz, constchar*key, size_tkey_length,

                   constchar*value, size_tvalue_length);

typedef LRC_RESULT (*LrcBuilderOnTimeTag)(LrcBuilder*thiz, size_tstart_time);

typedef LRC_RESULT (*LrcBuilderOnLrc)(LrcBuilder*thiz, constchar*lrc, size_tlrc_length);

typedef LRC_RESULT (*LrcBuilderEnd)(LrcBuilder*thiz);

typedef LRC_RESULT (*LrcBuilderDestroy)(LrcBuilder*thiz);

 

struct_LrcBuilder

{

   LrcBuilderBegin    on_begin;

   LrcBuilderOnIDTag  on_id_tag;

   LrcBuilderOnTimeTagon_time_tag;

   LrcBuilderOnLrc    on_lrc;

   LrcBuilderEnd      on_end;

   LrcBuilderDestroy  destroy;

 

   charpriv[1];

};

 

       实现一:

LrcBuilder*lrc_dump_builder_new(FILE*fp)

{

   LrcDumpBuilder* dataNULL;

   LrcBuilder* thiz = (LrcBuilder*)calloc(sizeof(LrcBuilder) + sizeof(LrcDumpBuilder), 1);

 

   if(thiz !=NULL)

   {

       thiz->on_begin    = lrc_dump_builder_on_begin;

       thiz->on_id_tag   = lrc_dump_builder_on_id_tag;

       thiz->on_time_tag = lrc_dump_builder_on_time_tag;

       thiz->on_lrc      = lrc_dump_builder_on_lrc;

       thiz->on_end      = lrc_dump_builder_on_end;

       thiz->destroy     = lrc_dump_builder_destroy;

       data = (LrcDumpBuilder*)thiz->priv;

       data->fp =fp != NULL ?fp : stdout;

   }

 

   returnthiz;

}

       实现二:

      

LrcBuilder*lrc_default_builder_new(void)

{

   LrcDefaultBuilder* dataNULL;

   LrcBuilder* thiz = (LrcBuilder*)calloc(sizeof(LrcBuilder) +sizeof(LrcDefaultBuilder), 1);

 

   if(thiz !=NULL)

   {

       thiz->on_begin    = lrc_default_builder_on_begin;

       thiz->on_id_tag   = lrc_default_builder_on_id_tag;

       thiz->on_time_tag = lrc_default_builder_on_time_tag;

       thiz->on_lrc      = lrc_default_builder_on_lrc;

       thiz->on_end      = lrc_default_builder_on_end;

       thiz->destroy     = lrc_default_builder_destroy;

       data = (LrcDefaultBuilder*)thiz->priv;

   }

 

   returnthiz;

}

 

类的三个层次:

类这个概念比较微妙,即使在软件开发领域,不同的人提到这个概念所指的内容也不一样。一些大师早就注意到了这一点,为了让这个概念在不同情况下,具有较准确的意义,他们建议从三个层次看待类这个概念:

 

1.         概念层(Conceptual)

这是一个较高的层次,通常在进行领域分析时,为了建立概念模型时使用。这时使用的术语是现实世界中的术语,而不是软件开发中的术语。在这个层次,类只是一个概念,加上一些不太严谨的特征说明,甚至只有一个名称。尽管它往往与软件开发中的类一一对应,便这种映射并不一定是直接的。

 

2.         规格层(Specification)

在这个层次,类已经是属于软件开发范畴了,但主要关注的是类的接口,而不是类的实现。此时你可能想到它的一组接口函数,而不关心这些函数是如何实现的。

 

3.         实现层(Implementation)

在这个层次,我们才真正关注类的实现,此时你可能会想到一些用某种语言写成的函数体,定义的成员变量等等。

 

面向对象的好处:

面向对象已经征服了软件开发的绝大部分领域,近几年来出现的面向方面的编程(AOP)、产生式编程(GP)和面向组件的开发等等,都提出了一些新的思维,在某些方面大提高了开发效率,但它们并非是取代了面向对象,相反是对面向对象的补充和完善,面向对象始终稳坐第一把交椅。

 

面向对象到底有何德何能,它凭借什么取代面向对程呢?封装、继承和多态到底有何种魔力,吸引众多的高手去完善它,让布道者们不厌其烦的颂扬它呢?归根结底,面向对象会带来两个好处,这两个好处正是设计者们一直在追求的:

 

1.         降低系统的复杂度。

众所周知,随着硬件的飞速发展,计算机的计算能力越来越强大,人们对软件期望也越来越高,而软件复杂度又与它的规模成指数倍数增长。软件复杂度可以说是软件开发的第一大难题,我们可以轻而易举的写出5000行代码,而面对100万行代码规模的软件,会有点让人觉得人的智力是多么有限。

 

而面向对象正是降低系统复杂度的好方法。首先它按类来组织系统,把系统分成几个大的部分,每个部分又由更小的子类组成,如此细分下去直到我们能轻易实现它为此,这种分而治之的方法符合人类解决复杂问题的习惯。

 

其次是它采用从抽象到具体的顺序来把握事物,抽象让我们用少量精力先掌握事物的共性,然后再去研究事物更具体的特性,这种逐渐细化的方法也是符合人类解决复杂问题的习惯的。

 

2.         隔离变化。

需求变化和技术变化也是软件开发所面临的两大难题。用户似乎从来不知道什么是他们真正的需求,或许他们真正的需求也是在变化的。技术可谓日新月异,我们不断的发明新技术,这些技术帮我们提高了生产力。但有时新技术也会砸到自己的脚,为了运用这些新技术,我们要花更多时间学习和工作。或者说创新只是满足了少数人的乐趣,让多数人吃了苦头。

 

只有变化才是永恒的,诅咒变化无济于事,面对它并搞掂它才是正途。大师也建议我们去拥抱变化,而不是逃避变化。面向对象正是拥抱变化的银弹之一,它不是尝试阻止变化的发生(对此谁也无能为力),而是努力去隔离变化。与整体比较,变化的部分毕竟只占很小的分量,如果这些变化被隔离开了,它不影响不变的部分的,变的部分独立变化,不会牵一发而动全身,这可以大大减少变化引起的麻烦。针对接口编程而不是针对实现编程,这是面对象的精髓,也是拥抱变化的良方。

 

~~~end~~

转载自http://blog.csdn.net/absurd/article/details/1067390

——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

C语言实现封装、继承和多态

Category: C/C++语言 View: 2,076 阅 Author: Dong

1、  概述

C语言是一种面向过程的程序设计语言,而C++是在C语言基础上衍生来了的面向对象的语言,实际上,很多C++实现的底层是用C语言实现的,如在Visual C++中的Interface其实就是struct,查找Interface的定义,你可以发现有这样的宏定义:

#ifndef Interface

#define Interface struct

#endif

C++在语言级别上添加了很多新机制(继承,多态等),而在C语言中,我们也可以使用这样的机制,前提是我们不得不自己实现。

本文介绍了用C语言实现封装,继承和多态的方法。

2、  基本知识

在正式介绍C语言实现封装,继承和多态事前,先介绍一下C语言中的几个概念和语法。

(1)    结构体

在C语言中,常把一个对象用结构体进行封装,这样便于对对象进行操作,比如:

1
2
3
4
5
6
7
strcut Point{
 
int x;
 
int y;
 
};

结构体可以嵌套。因而可以把一个结构体当成另一个结构体的成员,如:

1
2
3
4
5
6
7
struct Circle {
 
struct Point point_;
 
int radius;
 
};

该结构体与以下定义完全一样(包括内存布置都一样):

1
2
3
4
5
6
7
8
9
struct Circle {
 
int x;
 
int y;
 
int radius;
 
};

(2)    函数指针

函数指针是指针的一种,它指向函数的首地址(函数的函数名即为函数的首地址),可以通过函数指针来调用函数。

如函数:

int func(int a[], int n);

可以这样声明函数指针:

int (*pFunc)(int a[], int n);

这样使用:

pFunc = func;

(*pFunc)(a, n);【或者PFunc(a, n)】

可以用typedef定义一个函数指针类型,如:

typdef int (*FUNC)(int a[], int n)

可以这样使用:

int cal_a(FUNC fptr, int a[], int n)

{

//实现体

}

(3)    extern与static

extern和static是C语言中的两个修饰符,extern可用于修饰函数或者变量,表示该变量或者函数在其他文件中进行了定义;static也可用于修饰函数或者变量,表示该函数或者变量只能在该文件中使用。可利用它们对数据或者函数进行隐藏或者限制访问权限。

3、  封装

在C语言中,可以用结构+函数指针来模拟类的实现,而用这种结构定义的变量就是对象。

封装的主要含义是隐藏内部的行为和信息,使用者只用看到对外提供的接口和公开的信息。有两种方法实现封装:

(1)    利用C语言语法。在头文件中声明,在C文件中真正定义它。

这样可以隐藏内部信息,因为外部不知道对象所占内存的大小,所以不能静态的创建该类的对象,只能调用类提供的创建函数才能创建。这种方法的缺陷是不支持继承,因为子类中得不到任何关于父类的信息。如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//头文件:point.h
 
#ifndef POINT_H
 
#define POINT_H
 
struct Point;
 
typedef struct Point point;
 
point * new_point(); //newer a point object
 
void free_point(point *point_); // free the allocated space
 
#endif
 
//C文件:point.c
 
#include”point.h”
 
strcut Point
 
{
 
int x;
 
int y;
 
};
 
point * new_point()
 
{
 
point * new_point_ = (point *) malloc ( sizeof (point));
 
return new_point_;
 
}
 
void free_point(point *point_)
 
{
 
if (point_ == NULL)
 
return ;
 
free (point_);
 
}

(2)    把私有数据信息放在一个不透明的priv变量或者结构体中。只有类的实现代码才知道priv或者结构体的真正定义。如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#ifndef POINT _H
 
#define POINT_H
 
typedef struct Point point;
 
typedef struct pointPrivate pointPrivate;
 
strcut Point
 
{
 
Struct pointPrivate *pp;
 
};
 
int get_x(point *point_);
 
int get_y(point *point_);
 
point * new_point(); //newer a point object
 
void free_point(point *point_); // free the allocated space
 
#endif
 
//C文件:point.c
 
#include”point.h”
 
struct pointPrivate
 
{
 
int x;
 
int y;
 
}
 
int get_x(point *point_)
 
{
 
return point_->pp->x;
 
}
 
int get_y(point *point_)
 
{
 
return point_->pp->y;
 
}
 
//others…..

4、  继承

在C语言中,可以利用“结构在内存中的布局与结构的声明具有一致的顺序”这一事实实现继承。

比如我们要设计一个作图工具,其中可能涉及到的对象有Point(点),Circle(圆),由于圆是由点组成的,所有可以看成Circle继承自Point。另外,Point和Circle都需要空间申请,空间释放等操作,所有他们有共同的基类Base。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
//内存管理类new.h
 
#ifndef NEW_H
 
#define NEW_H
 
void * new ( const void * class , ...);
 
void delete ( void * item);
 
void draw ( const void * self);
 
#endif
 
//内存管理类的C文件:new.c
 
#include “new.h”
 
#include “base.h”
 
void * new ( const void * _base, ...)
 
{
 
const struct Base * base = _base;
 
void * p = calloc (1, base->size);
 
assert (p);
 
* ( const struct Base **) p = base;
 
if (base ->ctor)
 
{
 
va_list ap;
 
va_start (ap, _base);
 
p = base ->ctor(p, &ap);
 
va_end (ap);
 
}
 
return p;
 
}
 
void delete ( void * self)
 
{
 
const struct Base ** cp = self;
 
if (self && * cp && (* cp) —> dtor)
 
self = (* cp) —>dtor(self);
 
free (self);
 
}
 
void draw ( const void * self)
 
{
 
const struct Base * const * cp = self;
 
assert (self &&* cp && (* cp)->draw);
 
(* cp) ->draw(self);
 
}
 
//基类:base.h
 
#ifndef BASE_H
 
#define BASE_H
 
struct Base
 
{
 
size_t size; //类所占空间
 
void * (* ctor) ( void * self, va_list * app); //构造函数
 
void * (* dtor) ( void * self); //析构函数
 
void (* draw) ( const void * self); //作图
 
};
 
#endif
 
//Point头文件(对外提供的接口):point.h
 
#ifndef   POINT_H
 
#define  POINT_H
 
extern const void * Point;                /* 使用方法:new (Point, x, y); */
 
#endif
 
//Point内部头文件(外面看不到):point.r
 
#ifndef POINT_R
 
#define POINT_R
 
struct Point
 
{
 
const void * base; //继承,基类指针,放在第一个位置,const是防止修改
 
int x, y;        //坐标
 
};
 
#endif
 
//Point的C文件:point.c
 
#include “point.h”
 
#include “new.h”
 
#include “point.h”
 
#include “point.r”
 
static void * Point_ctor ( void * _self, va_list * app)
 
{
 
struct Point * self = _self;
 
self ->x = va_arg (* app, int );
 
self ->y = va_arg (* app, int );
 
return self;
 
}
 
static void Point_draw ( const void * _self)
 
{
 
const struct Point * self = _self;
 
printf (“draw (%d,%d)”, self -> x, self -> y);
 
}
 
static const struct Base _Point = {
 
sizeof ( struct Point), Point_ctor, 0, Point_draw
 
};
 
const void * Point = & _Point;
 
//测试程序:main.c
 
#include “point.h”
 
#include “new.h”
 
int main ( int argc, char ** argv)
 
{
 
void * p = new (Point, 1, 2);
 
draw(p);
 
delete (p);
 
}

同样,Circle要继承Point,则可以这样:

1
2
3
4
5
6
7
8
9
struct Circle
 
{
 
const struct Point point; //放在第一位,可表继承
 
int radius;
 
};

5、  多态

可以是用C语言中的万能指针void* 实现多态,接上面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
//测试main.c
 
void * p = new (Point, 1, 2);
 
void * pp = new (Circle, 1, 2);
 
draw(p); //draw函数实现了多态
 
draw(pp);
 
delete (p);
 
delete (pp);

6、  总结

C语言能够模拟实现面向对象语言具有的特性,包括:多态,继承,封装等,现在很多开源软件都了用C语言实现了这几个特性,包括大型开源数据库系统postgreSQL,可移植的C语言面向对象框架GObject,无线二进制运行环境BREW。采用C语言实现多态,继承,封装,能够让软件有更好的可读性,可扩展性。

7、  参考资料

(1)        《C语言中extern和static用法》:

http://www.cnblogs.com/hishope/archive/2008/08/28/1278822.html

(2)        《三、使用GObject——私有成员和静态变量》:

http://blog.csdn.net/wormsun/archive/2009/11/25/4874465.aspx

(3)        《技巧:用 C 语言实现程序的多态性》:

http://www.ibm.com/developerworks/cn/linux/l-cn-cpolym/index.html?ca=drs-

(4)        书籍《Object-Oriented Programming With ANSI-C》

8、  代码下载

本文中的代码可以在此处下载:代码下载

原创文章,转载请注明: 转载自董的博客

本文链接地址: http://dongxicheng.org/cpp/ooc/

________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

C语言下的封装、继承与多态

408人阅读 评论(0) 收藏 举报

     上次课,钱SIR提到,Liux下面也有很多用C实现的面向对象的结构。比较感觉兴趣,就在网上查了一些资料,原来C语言模拟实现面向对象语言所具有的特性:多态,继承,封装,也是一件很简单的事儿。并且现在很多开源软件都了用C语言实现了这几个特性,包括大型开源数据库系统postgreSQL,可移植的C语言面向对象框架GObject。

    在自己机器上实践了下,感叹C语言的灵活与强大!总结一下,以便交流:

 

一、基础知识

 

(1)结构体

结构体可以嵌套,因而可以把一个结构体当成另一个结构体的成员,如:

  1. struct Point{   
  2.  int x;   
  3.  int y;  
  4. };  
  1. struct Circle {   
  2. struct Point point_;   
  3. int radius;   
  4. };   

该结构体与以下定义完全一样(包括内存布置都一样

  1. struct Circle {   
  2.  int x;   
  3.  int y;   
  4.  int radius;   
  5. };  

 

(2)void *

指针是整个 C 语言的精髓所在。而你也一直敬畏着指针,又爱又恨地使用着它。许多教材都告诉你,int *叫做指向整型的指针,而 char *是指向字符型的指针,等等等等不一而足。然而这里有一个另类的指针家族成员——void *。不要按照通常的命名方式叫它做指向void 类型的指针,它的正式的名字叫做:可以指向任意类型的指针。

 

(3)C中的参数个数可变函数

可变参数函数的原型声明:

  1. type VAFunction(type arg1, type arg2, … );  

参数可以分为两部分:个数确定的固定参数和个数可变的可选参数。函数至少需要一个固定参数,固定参数的声明和普通函数一样;可选参数由于个数不确定,声明时用"..."表示。固定参数和可选参数公同构成一个函数的参数列表。

标准C/C++包含头文件stdarg.h,该头文件中定义了操作不定变量的相关宏:

  1. void va_start ( va_list arg_ptr, prev_param ); /* ANSI version */  
  2. type va_arg ( va_list arg_ptr, type );   
  3. void va_end ( va_list arg_ptr );   

在这些宏中,va就是variable argument(可变参数)的意思;
arg_ptr    是指向可变参数表的指针;
prev_param 指可变参数表的前一个固定参数;
type       为可变参数的类型。
va_list    也是一个宏,其定义为typedef char * va_list,实质上是一char型指针。

具体用法可以参考:http://blog.chinaunix.net/space.php?uid=9174178&do=blog&cuid=484548

 

二、封装

 

封装的主要含义是隐藏内部的行为和信息,使用者只用看到对外提供的接口和公开的信息。
在C语言中的实现方法:把私有数据信息放在一个不透明的priv变量或者结构体中,只有类的实现代码才知道priv或者结构体的真正定义。
例如:

头文件:

  1. //========头文件:Point.h文件========  
  2. #ifndef POINT_H  
  3. #define POINT_H  
  4. typedef struct Point point;  
  5. typedef struct pointPrivate pointPrivate;  
  6. <pre class="cpp" name="code">struct Point  
  7.   
  8. {  
  9.  struct pointPrivate *pp;};  
  10. int get_x(point *point_);  
  11. int get_y(point *point_);  
  12. point * new_point(int x,int y);  
  13. }  
  14. #endif  
源文件
  1. //=======C文件:Point.c文件========  
  2. #include "Point.h"  
  3. #include<stdlib.h>  
  4. struct pointPrivate;  
  5.  int x;  
  6.  int y;  
  7. };  
  8.   
  9. int get_x(point *point_){  
  10.  return point_->pp->x;  
  11. }  
  12.   
  13. int get_y(point *point_){  
  14.  return point_->pp->y;  
  15. }  
  16.   
  17. point* new_point(int x,int y){  
  18.  point* p=(point*)malloc(sizeof(point));  
  19.  p->pp=(pointPrivate*)malloc(sizeof(pointPrivate));  
  20.  p->pp->x=x;  
  21.  p->pp->y=y;  
  22.  return p;  
  23. }  
测试文件:
  1. int main()  
  2. {  
  3.     point* p = new_point(1,2);  
  4.     //printf("x:%d,y:%d\n",p->pp->x,p->pp->y);  
  5.     printf("x:%d,y:%d\n",get_x(p),get_y(p));  
  6. }  
在测试代码中,注释掉的一部分是编译不过的,因为我们已经把pointPrivate结构体的定义隐藏了。而且必须使用new_point来创建point结构对象,否则无法初始化point结构体中的pp成员变量。
有意思的是:这段代码生成的exe文件可能会被360误认为病毒。

 

三、继承

 

在C语言中,可以利用“结构在内存中的布局与结构的声明具有一致的顺序”这一事实实现继承。   比如我们要设计一个作图工具,其中可能涉及到的对象有Point(点),Circle(圆),由于圆是由点组成的,所有可以看成Circle继承自Point。另外,Point和Circle都需要空间申请,空间释放等操作,所有他们有共同的基类Base。

  1. //基类Base的内部头文件Base.r,对外隐藏  
  2. #ifndef BASE_R  
  3. #define BASE_R  
  4. #include <stdarg h="">  
  5. struct Base {  
  6.     size_t size;  
  7.     void * (* ctor) (void * self, va_list * app);//构造函数  
  8.     void * (* dtor) (void * self);   //析构函数  
  9.     void (* draw) (const void * self);//作图函数  
  10. };  
  11. #endif  
  12.   
  13. //Point的内部头文件Point.r,对外隐藏  
  14. #ifndef POINT_R  
  15. #define POINT_R  
  16. struct Point {  
  17.     const void * base;  //继承Base类,基类指针,放在第一个位置,const是防止修改  
  18.     int x, y;   //坐标  
  19. };  
  20. #define x(p) (((const struct Point *)(p)) -> x)  
  21. #define y(p) (((const struct Point *)(p)) -> y)  
  22. #endif  
  23.   
  24. //Point的头文件Point.h(对外提供接口)  
  25. #ifndef POINT_H  
  26. #define POINT_H  
  27. extern const void * Point;   /* new(Point, x, y); */  
  28. void move (void * point, int dx, int dy);  
  29. #endif  
  30.   
  31. //Point的源文件Point.c  
  32. #include <stdio h="">  
  33. #include "Point.h"  
  34. #include "Point.r"  
  35. #include "new.h"  
  36. #include "Base.r"  
  37. /**********Point类自己的构造函数***********/  
  38. static void * Point_ctor (void * _self, va_list * app){   
  39.     struct Point * self = _self;  
  40.     self -> x = va_arg(* app, int);  
  41.     self -> y = va_arg(* app, int);  
  42.     return self;  
  43. }  
  44. /**********Point类自己的绘图函数***********/  
  45. static void Point_draw (const void * _self){   
  46.     const struct Point * self = _self;  
  47.     printf("Point at %d,%d\n", self -> x, self -> y);  
  48. }  
  49. static const struct Base _Point = {  
  50.     sizeof(struct Point), Point_ctor, 0, Point_draw  
  51. };  
  52. const void * Point = & _Point;  
  53. void move (void * _self, int dx, int dy){   
  54.     struct Point * self = _self;  
  55.     self -> x += dx, self -> y += dy;  
  56. }  
  57.   
  58. //Circle内部头文件Circle.r,对外隐藏  
  59. #ifndef CIRCLE_R  
  60. #define CIRCLE_R  
  61. #include "Point.r"  
  62. struct Circle {   
  63.     const struct Point _;  //继承Point类,需放在第一位  
  64.     int rad;   
  65. };  
  66. #endif  
  67.   
  68. //Circle的头文件Circle.h(对外提供接口)  
  69. #ifndef CIRCLE_H  
  70. #define CIRCLE_H  
  71. #include "Point.h"  
  72. extern const void * Circle;  /* new(Circle, x, y, rad) */  
  73. #endif  
  74.   
  75. //Circle的源文件Circle.c  
  76. #include <stdio h="">  
  77. #include "Circle.h"  
  78. #include "Circle.r"  
  79. #include "new.h"  
  80. #include "Base.r"  
  81. /**********Circle类自己的构造函数***********/  
  82. static void * Circle_ctor (void * _self, va_list * app){   
  83.     struct Circle * self = ((const struct Base *) Point) -> ctor(_self, app);  
  84.     self -> rad = va_arg(* app, int);  
  85.     return self;  
  86. }  
  87. /**********Circle类自己的绘图函数***********/  
  88. static void Circle_draw (const void * _self){   
  89.     const struct Circle * self = _self;  
  90.     printf("circle at %d,%d rad %d\n",x(self), y(self), self -> rad);  
  91. }  
  92. static const struct Base _Circle = {  
  93.     sizeof(struct Circle), Circle_ctor, 0, Circle_draw  
  94. };  
  95. const void * Circle = & _Circle;  
  96.   
  97. //内存管理类头文件new.h(对外提供接口)  
  98. #ifndef NEW_H  
  99. #define NEW_H  
  100. void * new (const void * base, ...);  
  101. void delete (void * item);  
  102. void draw (const void * self);  
  103. #endif  
  104.   
  105. //内存管理类的源文件:new.c  
  106. #include <assert h="">  
  107. #include <stdlib h="">  
  108. #include <stdarg h="">  
  109. #include "Base.r"  
  110. void * new (const void * _class, ...){   
  111.     const struct Base * base = _class;  
  112.     void * p = calloc(1, base -> size);  
  113.     assert(p);  
  114.     * (const struct Base **) p = base;  
  115.     if (base -> ctor){   
  116.         va_list ap;  
  117.         va_start(ap, _class);  
  118.         p = base -> ctor(p, & ap);  
  119.         va_end(ap);  
  120.     }  
  121.     return p;  
  122. }  
  123. void delete (void * self){   
  124.     const struct Base ** cp = self;  
  125.     if (self && * cp && (* cp) -> dtor)  
  126.         self = (* cp) -> dtor(self);  
  127.     free(self);  
  128. }  
  129. void draw (const void * self){   
  130.     const struct Base * const * cp = self;  
  131.     assert(self && * cp && (* cp) -> draw);  
  132.     (* cp) -> draw(self);  
  133. }</stdarg></stdlib></assert></stdio></stdio></stdarg>  
四、多态可以是用C语言中的万能指针void* 实现多态,接上面的例子:
  1. #include "Circle.h"  
  2. #include "new.h"  
  3. int main (int argc, char ** argv)  
  4. {     
  5.     void * p;  
  6.     int i;  
  7.     for(i=0; i<2; i++)  
  8.     {  
  9.         if(i==0)  
  10.             p = new(Circle, 1, 2, 3);  
  11.         else  
  12.             p = new(Point, 1, 2);  
  13.         draw(p);  
  14.         move(p, 10, 20);  
  15.         draw(p);  
  16.         delete(p);  
  17.     }  
  18.     return 0;  
  19. }  
输出结果:
circle at 1,2 rad 3
circle at 11,22 rad 3
Point at 1,2
Point at 11,22

 

五、总结

 

面向对象是一种程序设计思想,而 C 语言则是一种编程语言。也许它并不是专门为了面向对象编程而设计,但是这绝不意味着它不能实现面向对象的程序设计。当然以上所展示的这几个操作,如果是用别的编程语言,可能只要寥寥几行就可以完成,但是 C 语言想告诉我们的是:也许我不擅长,但是并不意味着我做不到。

 

注:

有些头文件名被csdn误认为内部命令,而变很很诡异,请以所下载的代码为准。

下载本文所有代码

转载自http://blog.csdn.net/liql2007/article/details/6866972


________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

C语言这样封装继承多态也挺好的。

C代码   收藏代码
  1. #include <stdio.h>  
  2. #include <conio.h>  
  3. #define MAX 10  
  4.   
  5. typedef struct Animal{  
  6.     void *this;  
  7.     char name[MAX];  
  8.     void (*shout)(struct Animal *);  
  9. }Animal;  
  10.   
  11. typedef struct Swimmable{  
  12.     void *this;  
  13.     void (*swim)(struct Swimmable *);  
  14. }Swimmable;  
  15.   
  16. typedef struct Dog{  
  17.     Animal *Animal;  
  18.     Swimmable *Swimmable;  
  19. }Dog;  
  20.   
  21. typedef struct Cat{  
  22.     Animal *Animal;  
  23.     Swimmable *Swimmable;  
  24. }Cat;  
  25.   
  26. void shout_Cat(Animal *cat){  
  27.     printf("%s miaomiao.\n", cat->name);  
  28. }  
  29.   
  30. void swim_Cat(Swimmable *cat){  
  31.     printf("%s cannot swim.\n", ((Cat *)(cat->this))->Animal->name);  
  32. }  
  33.   
  34. void shout_Dog(Animal *dog){  
  35.     printf("%s wangwang.\n", dog->name);  
  36. }  
  37.   
  38. void swim_Dog(Swimmable *dog){  
  39.     printf("%s can swim.\n", ((Dog *)(dog->this))->Animal->name);  
  40. }  
  41.   
  42. void visit_Animal(Animal *animal){  
  43.     animal->shout(animal);  
  44. }  
  45.   
  46. void visit_Swimmable(Swimmable *swimmable){  
  47.     swimmable->swim(swimmable);  
  48. }  
  49.   
  50. void initialize_Dog(Dog* dog, char *name){  
  51.     dog->Animal = (Animal *) malloc(sizeof(Animal));  
  52.     dog->Animal->this = dog;  
  53.     dog->Animal->shout = shout_Dog;  
  54.     strcpy(dog->Animal->name, name);  
  55.     dog->Swimmable = (Swimmable *) malloc(sizeof(Swimmable));  
  56.     dog->Swimmable->this = dog;  
  57.     dog->Swimmable->swim = swim_Dog;  
  58. }  
  59.   
  60. void initialize_Cat(Cat* cat, char *name){  
  61.     cat->Animal = (Animal *) malloc(sizeof(Animal));  
  62.     cat->Animal->this = cat;  
  63.     cat->Animal->shout = shout_Cat;  
  64.     strcpy(cat->Animal->name, name);  
  65.     cat->Swimmable = (Swimmable *) malloc(sizeof(Swimmable));  
  66.     cat->Swimmable->this = cat;  
  67.     cat->Swimmable->swim = swim_Cat;  
  68. }  
  69.   
  70. void finalize_Dog(Dog *dog){  
  71.     free(dog->Animal);  
  72.     free(dog->Swimmable);  
  73. }  
  74.   
  75. void finalize_Cat(Cat *cat){  
  76.     free(cat->Animal);  
  77.     free(cat->Swimmable);  
  78. }  
  79.   
  80. void main(){  
  81.     Dog dog;  
  82.     Cat cat;  
  83.     clrscr();  
  84.     initialize_Dog(&dog, "Wangcai");  
  85.     initialize_Cat(&cat, "Kitty");  
  86.     visit_Animal(dog.Animal);  
  87.     visit_Animal(cat.Animal);  
  88.     visit_Swimmable(dog.Swimmable);  
  89.     visit_Swimmable(cat.Swimmable);  
  90.     finalize_Dog(&dog);  
  91.     finalize_Cat(&cat);  
  92. }  


所有的面向对象的设计模式也都能类似实现。
虽然没有C++那么方便地面向对象,但是灵活性更强,如可以让多个实例共享一个父实例等。

转载自http://www.iteye.com/topic/699588

________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

【jixingzhong】:
[Ref]

#include <stdio.h>
#include <stdlib.h>

#define VIRTUAL

struct vtable /*虚函数表*/
{
       int (*p_geti)(void *); /*虚函数指针*/
       void (*p_print)();  /*虚函数指针*/
};

struct shape /*类shape*/
{
       void *vptr; /*虚表指针 - 指向vtable*/
       int i;
};

struct circle /*类circle*/
{
       void *vptr; /*虚表指针 - 指向vtable*/
       int i;
};

struct rectangle /*类rectangle*/
{
       void *vptr; /*虚表指针 - 指向vtable*/
       int i;
};

//------------------------------------
//print() - 虚函数 
/*真正调用的函数,在其内部实现调用的多态*/
VIRTUAL void print(void *self) /*参数是对象指针*/
{
     const struct vtable * const *cp = self;
     (*cp)->p_print();
}

void shape_print()
{
     printf("this is a shape!\n");
}

void circle_print()
{
     printf("this is a circle!\n");
}

void rectangle_print() 
{
     printf("this is a rectangle!\n");
}

//------------------------------------------------------
//geti() - 虚函数 
VIRTUAL int geti(void *self)
{
    const struct vtable * const *cp = self;
    return (*cp)->p_geti(self);     /*这一行出问题*/
}

int shape_geti(struct shape *self) /*具体函数实现时,参数还要是其类型指针*/
{
    return self->i;
}

int circle_geti(struct circle *self) /*具体函数实现时,参数还要是其类型指针*/
{
    return self->i;
}

int rectangle_geti(struct rectangle *self) /*具体函数实现时,参数还要是其类型指针*/
{
    return self->i;
}


int main(int argc, char *argv[])
{
  struct shape _shape; /*shape的对象_shape*/
  struct circle _circle; /*circle的对象_circle*/
  struct rectangle _rectangle; /*rectangle的对象_rect*/
  
  /*声名虚表*/
  struct vtable shape_vtable; /*shape对象的vtable*/
  struct vtable circle_vtable; /*circle对象的vtable*/
  struct vtable rectangle_vtable; /*rectangle的虚表*/
  
  /*给类分配虚表*/
  _shape.vptr = &shape_vtable; /*将虚表挂上*/
  _circle.vptr = &circle_vtable; /*将虚表挂上*/
  _rectangle.vptr = &rectangle_vtable; /*将虚表挂上*/
  
  /*给虚表对应相应的函数*/
  shape_vtable.p_print = shape_print; /*赋值相应的函数*/
  circle_vtable.p_print = circle_print; /*赋值相应的函数*/
  rectangle_vtable.p_print = rectangle_print; /*赋值相应的函数*/
  
  /*给虚表对应相应的函数*/
  shape_vtable.p_geti = shape_geti;
  circle_vtable.p_geti = circle_geti;
  rectangle_vtable.p_geti = rectangle_geti;
  
  /*动态联编实现多态*/
  /*因类型的不同而作出不同的反映*/
  print(&_shape);
  print(&_circle);
  print(&_rectangle);
  
  _shape.i = 5;
  _circle.i = 19;
  _rectangle.i = 1;
  
  /*动态联编实现多态*/
  /*因类型的不同而作出不同的反映*/
  printf("_shape's i is : %d\n", geti(&_shape));
  printf("_circle's i is : %d\n", geti(&_circle));
  printf("_rectangle's i is : %d\n", geti(&_rectangle));
  
  system("PAUSE");
  return 0;
}

//   From  http://www.programfan.com/club/showpost.asp?id=25794

——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

另外还有一本关于这方面的英文的书听说蛮好的 《Object-Oriented Programming With ANSI-C》  新浪爱问共享资料有免费下载http://ishare.iask.sina.com.cn/f/10797511.html


C语言模式实现C++继承多态 C语言模式实现C++继承多态 描述: C实现一个struct A和struct B各包含一个int成员a和b,要求达到B继承了A的效果,也就是B里面包含一个A。并且能达 到多态的效果,也就是一个A*p指向A调的是A的函数,指向B调用的是B的函数。 C++中的继承多态 继承面向对象复用的重要手段。通过继承定义一个类,继承是类型之间的关系建模,共享公有的东西,实现各自本质 阅读详情

相关推荐

C实现封装,继承,多态

用C语言实现 C++封装继承多态,网络上的资源,我们一起感谢未留名的前辈。

《SICP》读后感:关于软件本质的一点思考

摘要:软件本身不是目的,人类的需求才是目的,而软件只是达到目的的手段。 软件的本质在于控制复杂性,这个复杂性并非来自于计算机,也并非来自于现实世界,而是来自于人类的思维和知识体系。 软件被使用的广泛性,在于它所满足的人类需求的广泛性。 什么是软件? 从一个简单的例子说起,比如我想计算两个数的和,于是写下这样的python代码 print a + b 但是,这段代码是我的最终...

weixin_30808693的博客 191

政府如何高效筛选优质科技项目以优化资源配置?.docx

政府如何高效筛选优质科技项目以优化资源配置?

面向对象编程的理解

学java很多年了,工作中也用了2年,始终对这三大机制似懂非懂,这次抛砖引玉,希望看看大家的意见。 从工程的角度说,为了避免软件危机,程序员需要相互协作。从效率的角度上说,需要代码复用。从设计的角度上来说, 需要高内聚低耦合。从扩展的角度来说,需要考虑设计模式。 继承 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为什么要采用面向对象技术?这道题目的答案...

ding_fang的博客 652

C语言实现封装继承多态

作者:Dong | 可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明 网址:http://dongxicheng.org/cpp/ooc/ 1、  概述 C语言是一种面向过程的程序设计语言,而C++是在C语言基础上衍生来了的面向对象语言,实际上,很多C++实现的底层是用C语言实现的,如在Visual C++中的Interface其实就是struct,查找Interfac

铁匠Smith先生的专栏 2635

图说C++对象模型:对象内存布局详解

0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局、虚表指针、虚基类指针等有深入了解的朋友可以慢慢看。 本文的结论都在VS2013上得到验证。不同的编译器在内存布局的细节上可能有所不同。 文章如果有解释不清、解释不通或疏漏的地方,恳请指出。 1.何为C++对象模型? 引用《深度探索C++对象模型》这本书中的话: 有两个概念可以解释C++对象模型: 语言中直接支持面向对象程...

weixin_34272308的博客 1451

OOC-用C实现面向对象

转自http://dongxicheng.org/cpp/ooc/ 这个其实就是ooc那本书上写的,感谢作者的辛勤劳动。 1、  概述 C语言是一种面向过程的程序设计语言,而C++是在C语言基础上衍生来了的面向对象语言,实际上,很多C++实现的底层是用C语言实现的,如在Visual C++中的Interface其实就是struct,查找Interface的定义,你可以发

yuyin86的专栏 1368

面向对象与面向过程的白话解释

简介: 面向对象,简称OO是一种以事物为中心的编程思想。 面向过程,简称PO是一种以过程为中心的编程思想。 实例: 针对面向对象的编程思想,是以具体事物为出发点,例如:车,包括汽车、公交车、卡车每一种车就是一个对象,那么这个对象都会有着共同的特征,汽车的形状、载人数量等,我们通根据这些对象和特征进行编程。 而面向过程的思想是相当于一条流水线,车的起火到熄火根据这一过程进行编程。 区别:...

拼命小李博客 855

C#-struct实例字段的内存布局(Layout)和大小(Size)

struct实例字段的内存布局(Layout)和大小(Size)        在C/C++中,struct类型中的成员的一旦声明,则实例中成员在内存中的布局(Layout)顺序就定下来了,即与成员声明的顺序相同,并且在默认情况下总是按照结构中占用空间最大的成员进行对齐(Align);当然我们也可以通过设置或编码来设置内存对齐的方式.        然而在.net托管环境中,CLR提供了更

MasterFT的专栏 2万+

合理改变结构体体元素声明顺序,节省内存空间

#include &lt;stdio.h&gt; typedef struct Goods { char a[18];//18 double b;//8 char c;//1 int d;//4 short e;//2 }Goods; ...

4126

软件设计本质论(Essential Design)白话面向对象

软件设计本质论(Essential Design)白话面向对象 转载时请注明出处:http://blog.csdn.net/absurd/ 不同的人在谈面向对象编程(OOP)时所指的含义并不相同。有人认为任何采用图形界面的应用程序都是面向对象的。有人把它作为术语来描述一种特别的进程间通信机制。还有人使用这个词汇是另有深义的,他们其实是想说:“来啊,买我的产品吧!”我一般不提OO

国产开源 GUI 引擎 AWTK 8121

白话文带你了解 封装 继承 多态

这里讲的仅仅是带你理解 封装 继承 多态 染好您可以移步去别的文章学习具体的实现 (只是个人理解 您可以不爱,请别伤害哦!) 首先你要知道 java是面向对象的,说白了就是我拿你当个人,请认清你的地位。 而面向过程是什么意思呢,我拿你当个机器,你牛你就给我好好完成功能的实现OK。 1. 来吧聊一聊封装 封装就像是我们去餐厅吃饭昂。 老板:谁TM买小米粥。 我走到窗口前去和老板说(你不走到窗口前你也没办法买不是,排除外卖昂)。 我:窝窝头儿,给我拿4个。 于是封装就来了 老板 准备各种材料 ,材料你也看不见,

weixin_41677268的博客 898

白话解析分布式系统,小白也能看懂

西方诗歌有云,无人是孤岛,你我心相系。今天,这句话同样适用于计算机。我们身边的服务器,个人电脑以及数据存储一直都在彼此通信。其实,我们每天使用的(和在开发的)应用和服务也都是构成完整系统的计算元素,彼此进行着交互,尽管很多时候我们感知不到。对这些系统及其运行原理的研究属于分布式计算的一部分,而分布式计算又是分布式系统的核心所在。一方面,我们可以把分布式系统看作计算机科学的扩展或继续,它通常涉及问题...

cpongo011702 458

Go语言下的多态

文章节选自《Go语言实战》 多态 现在了解了接口和方法集背后的机制,最后来看一个展示接口的多态行为的例子,如代码所示。 01 // 这个示例程序使用接口展示多态行为 02 package main 03 04 import ( 05 "fmt" 06 ) 0708 // notifier 是一个定义了 09 // 通知类行为的接口 10 type notifier interface {...

841

Win10 WSL安装ubuntu

本文面向 Windows 10/11 用户,介绍 WSL(Windows Subsystem for Linux)的常用命令、Ubuntu 的安装步骤,以及镜像的导出与导入方法,帮助你在 Windows 环境中快速搭建和使用 Linux 开发环境。

Golden_Chen的专栏 266

03 嵌入式操作系统 | 常用命令Ⅰ:文件、查找与压缩

一句话概述:掌握文件与目录的增删改查、内容查看、文本查找以及打包压缩常用命令,配套课堂练习与课后作业。 本节目标 能用 cp、mv、rm、mkdir、touch 操作文件与目录 会用 cat、head、tail、grep 查看和筛选文件内容 会用 tar 打包压缩并解压文件

weixin_43951955的博客 199

C题 数字存储示波器_全国大学生竞赛组委会.rar

C题 数字存储示波器_全国大学生竞赛组委会.rar

东信身份证阅读器机具统信UOS国产系统麒麟990CPU处理器web网页浏览器安装驱动SDK开发包

东信身份证阅读器机具统信UOS国产系统麒麟990CPU处理器web网页浏览器安装驱动SDK开发包 安装包基础概述 cn.donsee.eserver-2.0.0.1-uos1060-arm64-kirin990-20260608.deb 是东信国产化通用服务端DEB安装包,专为ARM架构国产化终端设备打造,适配统信UOS系统平台,主要用于国产嵌入式终端、国产化办公设备的后台服务部署。软件版本为2.0.0.1,于2026年6月8日编译发布,针对麒麟990硬件平台深度定制优化,运行轻量高效、兼容性稳定,是信创智能终端读卡业务的核心配套组件。 核心功能与应用场景 该服务端主要负责终端后台业务调度、数据采集、设备联动及数据上传,集成全品类卡片读取能力,支持居民身份证、外国人永久居留身份证、港澳台居民居住证、二代/三代社保卡、银行卡、普通居住证,以及M1卡、CPU卡、IC卡、15693卡等各类智能卡识别读取,可满足政务采集、民生核验、身份登记等多场景读卡需求。 产品广泛应用于政务服务、社区采集、国企窗口、基层民生核验等信创场景,解决国产ARM终端读卡适配差、服务不稳定、数据采集异常等问题,依托纯国产化软硬件环境,全程自主可控,保障业务数据安全合规。 东信身份证阅读器机具统信UOS国产系统麒

上一篇: 横空出世,席卷互联网--评微软等公司数据结构+算法面试100题
下一篇: 从文件 I/O 看 Linux 的虚拟文件系统
苏嵌杭天龙
博客等级 码龄16年 44粉丝 9原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值