数据的封装性及其可以进行操作的限制问题

来源:互联网 发布:阿芙 知乎 编辑:程序博客网 时间:2024/06/05 11:34

数据的封装性及其可以进行操作的限制问题


面向对象程序设计的最大特点就是实现了数据的封装,对数据的操作是受一定的限制的,那么,C++中是如何实现这些限制呢?

(数据的封装性,通过一些手段(限制)哪些数据量允许什么对其操作)

 

1.变量的作用域方法实现一种限制

一个变量的变量作用域:是从定义处开始(申请空间,用于存放数值),到遇到的 第一个“}”,该变量被释放空间。从定义处开始,到释放空间结束,可以对该变量进行操作使用,否则,该变量没有被定义,不能使用。

一般来讲,作用域有如下几种:

(1)函数原型作用域

函数原型声明中形参变量的作用域起于函数原型声明的左括号,结束于函数原型声明的右括号。

 

(2)块作用域(局部作用域)

块作用域是从块内的定义处开始,直到该块结束(即所在复合语句的右花括号)为止

 

(3)函数作用域

函数中定义的标示符具有函数作用域。仅在本函数中有效。

 

(4)类作用域(在后面专门介绍)

 

(5)文件作用域。

在函数之外声明的标识符具有文件作用域。

具有文件作用域的标识符,在整个程序文件中均有效,但在其他文件中无效。

具有文件作用域的标识符,其作用域开始于声明处,结束于该文件的结束处。

 

 

2.变量的存储类型方法实现一种限制

变量的存储类型指变量在内存中的存储方法。

Auto:采用堆栈方式分配内存空间,属于暂时性存储,其存储空间可以被若干变量多次覆盖使用

 

Register:存放在通用寄存器中

 

Extern:在所有函数和程序段中都可以引用

 

Static:在内存中是以固定地址存放的变量,在整个程序运行期间都有效

 

 

 

 

3.采用静态成员(类成员)方法实现限制

静态成员提供了同一个类不同对象数据成员的共享机制。

静态成员包括:静态数据成员,静态成员函数。

(1)静态数据成员必须要初始化:格式:  类型类名::静态数据成员=初值;

(2)静态成员函数可以直接访问该类的静态数据成员和成员函数,而访问非静态数据成员则可以通过对象进行调用。

 (3)静态数据成员可以被该类的所有函数访问;

4.采用友元的方法实现可以访问类的私有成员

5.类的定义:

(1)public:有什么作用,允许“谁”可以使用?

(2)private:有什么作用,允许“谁”可以使用?

(3)procted::有什么作用,允许“谁”可以使用?

可以使用类成员的有两类数据:成员函数,该类的对象,对于上述3种情况“谁”可以使用?

6.类的继承与派生:

   三种继承方式,对派生类各有什么影响?派生类可以直接使用的成员有哪些?派生类的对象可以直接使用哪些? 

 

 

 

C++ code到运行程序

作为一个c++程序员这个应该是最应该知道的细节,简言之:编译----链接----可执行的程序。这里所说的细节主要是第一步的细节,编译器如何把c++代码编译成目标代码。概括的讲是把c++代码转化成cpu能认识的东西。这个过程十分的复杂,需要解析c++标准这个庞大的语法体系,还要支撑起面向对象中的一些特性,比如继承,多态,封装等等,这个过程也由于编译器不同而不同,虽然都是c++编译器,编译出来的代码是不同的,这就导致了一些问题。因为c++标准并没有定义编译完成之后的代码的规范。这便造成了一些技术的诞生。也可以看出c++标准是针对程序员而言的,c++标准约束程序员,编译器来解析c++标准,来实现它,然而有意思的事情是c++支持指针,这个东西可以直接访问内存,这就相当于c++提供了一个后门来破坏自己定义的语言特性。可以通过这个“后门”来直接访问内存里的东西,但是一般的状况是程序崩溃,这是因为对内存的结构不是十分清楚的缘故,如果你能了解内存的布局,就可以超越c++语言的特性,利用编译器来做自己任何想做的事情了。

理解封装

C++的一个特性,相信很多的人自认为理解,完全的理解,至少以前的我是这么认为的,在三个特性中我认为封装性最容易理解,但是随着对面向对象的了解和认识,我对封装性有了新的认识,感觉以前的认识十分的片面。正如上面所说封装性是c++语言的特性,而语言是用来约束程序员的,以前的理解就是类像一个包,而里面有一些数据,程序员的代码不能随便访问。然而这种封装是比较片面的。

Everything has apurpose,而封装存在的理由就是重用,重用就是写的一个代码库可以在很多地方重用,而且易于扩充。在一块内存中可以被许多应用程序运用,从开发的角度这样十分的省事,不必做重复的工作,在使用的角度,十分的节约内存,以前一个程序要加载一个库,现在几个程序只需加载一个库就可以了。这就是重用,使用以前的概念是无法实现这个目的的。聪明的程序员解决了这个问题。使用com组件技术,做到了二进制级别的代码重用。相当于扩充了操作系统,因为操作系统就是一个开放的接口,供应用程序调用功能。这就需要二进制级别的封装,

而由于一样的c++代码由不同的编译器编译出来的代码不一样,造成了代码之间的兼容问题。因为你封装起来的东西给了使用不同编译器的程序员获得的代码是不一样的,这样就不具备扩充性和灵活性。不能实现代码重用。

所以c++语言级别的封装性是十分狭隘的。

各种角度看封装

用户:我只需要个能用的,能升级的产品。

客户程序员:我需要的是可扩展的,封装的,插件式的库,这个库的东西不能影响到程序框架中的其他部分

库程序员:给客户程序员一个接口和一个二进制级别的代码。以实现可扩充行和可重用性。

内存:对我而言没有封装,计算机的一个基本概念,越往底层限制的东西越少。

编译器:我编译出来的代码要具有封装性,必须处理我和同行之间的差异。

C++语言:无辜的我是用来限制程序员的。但是也可以使用我的巧妙规则开提高你的水平,来实现你所需要的重用和扩充性。

《C++面向对象程序设计》课程中

 

“封装”性概念自学指导设计

 

 

 

“封装”性概念是中央电大开放教育“计算机科学与技术专业”必修课《C++面向对象程序设计》中重点与难点内容之一。理解了“

 

封装性”概念,可以加深对面向对象程序设计思想理解,进一步掌握C++程序设计语言中“类”、“对象”、“友元”等概念。

 

一、问题的提出

 

在几年从事开放教育《C++面向对象程序设计》课程的教学中发现,开放教育本科同学对“封装”性概念理解较难。究其原因是由于

 

他们在过去所接受的教育中已经习惯了面向过程的程序设计思想,例如部分同学学习过汇编语言、C、Pascal或者basic语言,有的

 

同学还能使用诸如Foxbase、Foxpro等数据库管理系统开发一些简单的应用程序等所致。为了分解学习中的难点,便于学生的自主学

 

习,设计了对“封装性”概念的自主学习指导。

 

二、“封装”性概念自学指导设计的任务

 

学生自主学习成功的关键是在导师的导读指引下,按本课程的实施细则中自学计划认真自学。自学指导设计的任务是采用一种可以

 

便于同学们自学、融会贯通本部分知识的方法,使同学们理解和掌握这一部分知识。

 

1、“封装”性概念的自学目标

 

理解封装性是面向对象方法中的一种重要特征;

 

辨清对象的私有成员与封装;

 

理解友元的作用与封装

 

2、“封装”性的自学过程

 

复习已经学习过的相关知识,从中提炼“封装”性实例;

 

通过具体范例程序体会“封装”性概念;

 

总结与提高。

 

三、设计过程

 

1、引入概念

 

“封装”性概念是在第九章“面向对象程序方法”中提出,在后续章节中使用的。

 

自学中首先要理解封装性是将基本数据和对此数据进行操作的过程和函数结合起来,可以保证各软件部件具有良好的模块性的基础

 

(对象)——即其包装性;其次是这个模块性基础将尽可能对外界公布一个有限的界面,而将其细节隐藏起来,与其他对象的交往

 

通过这个界面进行——信息隐藏性。

 

通过生活实例理解“封装性”概念。

 

一个公司(或企业)的经营活动可以理解为一个“封装性”的概念。该公司的基本活动可以由其各部门(基本数据)和调度部门(

 

对此数据操作的过程)或共同完成的产品(函数)结合起来。各部门之间的(外界)联系是由公司总调度(或领导)和各部门调度

 

(或部门领导)实现的。

 

加深概念理解,对“封装”性概念要从三个方面理解。

 

⑴所有软件的内部都应有明确的范围,清楚的外部边界;这就象公司的各部门有明确的职责范围、各部门之间有确定的权限界限。

 

⑵每个软件部件都应具有友好的界面或接口,以表明软件部件之间的相互作用和相互联系;这就象公司的各部门相互间的衔接工序

 

及各部门之间有联系与制约。

 

⑶完成、保护和隐藏软件的内部实现,用户不必了解其具体的实现;这就像一个工厂的各个车间生产不同的零部件,本车间完成自

 

己的工作,对外提供成品零部件,使用零部件者不必知道其生产过程。

 

理解“封装”性的好处。

 

有了封装性,软件设计人员可以集中精力考虑开发系统各模块之间的关系等重大问题,而模块内部的实现可得到程序设计人员的研

 

究与完善,可以充分保证模块质量和可靠性,也支持软件工程化思想。

 

2、通过实例巩固概念通过总结加深概念

 

在教材的第十章“类与对象”中是封装性的具体体现。在这里我们可以看到对象通过类来定义。也就是说,类是进行封装和数据隐

 

藏的工具,进行数据和方法封装的基本逻辑单位。类中可以定义公有成员、保护成员和私有成员。公有成员可被任何函数访问;保

 

护成员可被该类的成员函数和相应的友元函数引用;而私有成员则只能为相应类的成员函数和相应的友元函数引用。引入私有成员

 

封装性和友元封装性的实例:

 

⑴通过对象的私有成员实例理解封装

 

#include

 

class personnel

 

{ public:

 

personnel (int mon)

 

{ money=mon;

 

}

 

void get_salary (personnel&p,int mon)

 

{ p.money-+mon;

 

money +=mon;

 

}

 

int get_mon ()

 

{ return money;

 

}

 

private:

 

int money; //私有成员

 

};

 

void main() {

 

personnel boss(1000); // 创建boss时付给其1000元

 

personnel employee(0);

 

cout<<”Beforeget_salary,boss:”<

<<”employee:”<

employee.get_salary(boss,200);// employee从boss领取200元

 

cout<<”Afterget_salary,boss:”<

<<”employee:”<

}

 

运行结果:

 

Before get_salary,boss: 1000employee: 0

 

After get_salary,boss: 800employee: 200

 

通过这个实例我们看到:在程序中定义了一个表示公司所有职员的personnel类,其中的成员函数get_salary(personnel &p,int

 

mon)可以改变私有成员money。在主函数中,首先在创建boss 时付给其1000元,employee从boss领取200元,即执行

 

employee.get_salary(boss,200)之后,employee的money增加了200元;而boss的money减少了200元。Employee通过成员函数操作改

 

变了boss的money。

 

上述实例告诉我们:程序编译过程中,编译器认为通过personnel &p的声明,p本身已经属于personnel 类,在get_salary

 

(personnel &p,int mon)中直接操作其私有数据成员属合法操作,如果有非成员函数对其进行操作就属于非法了。

 

⑵通过友元的实例理解封装

 

#include

 

#include

 

class point //定义一个类

 

{ public:

 

point (float xi,float yi)

 

{ X=xi,Y=yi;

 

}

 

float Get_X() {return X;}

 

float Get_Y() {return Y;}

 

friend float distance (point&a,point &b); //声明为类的友元

 

private:

 

float X,Y; //类的私有成员

 

};

 

float distance (point&a,point &b)

 

{

 

float dx = a.X-b.X; //因为是友元函数而访问类的私有成员X

 

float dy = a.Y-b.Y; //因为是友元函数而访问类的私有成员Y

 

return sqrt (dx*dx+dy*dy);

 

}

 

void main() {

 

pointp1(3.0,5.0),p2(4.0,6.0); //创建类的对象

 

float d = distance (p1,p2);//通过友元函数访问类的私有成员

 

cout <<”The distanceis:”<

}

 

运行结果:

 

The distance is:1.41421

 

在上面的例子中,我们看到只使用了float d = distance (p1,p2)就完成了对point类的对象p1和p2的访问。如果不采用友元,主函

 

数应该增加:

 

float dx =p1.Get_X()-p2.Get_X();

 

float dy =p1.Get_Y()-p2.Get_Y();

 

float distance =sqrt(dx*dx+dy*dy);

 

才能完成上述程序的功能。由此可见引入友元后可以简化程序设计者的烦琐工作。

 

3、通过总结加深概念

 

当同学们按照上述两步完成自学后,应当根据自己的体会进行总结。下面是引导性总结提纲:

 

⑴在C++面向对象程序设计语言中封装单元是什么?(类型)

 

⑵判断多个对象是否属于同一类的依据是什么?(是否符合相同的类型系统)

 

⑶程序中相同类的不同实例对象之间是否可以互访对方的私有成员?(可以——例1)

 

⑷引入友元的优点是什么?(节省成员函数调用的开销,提高程序效率——例2)

 

⑸类的设计者是否必须在考虑好该类的各种可能的使用情况后才能开始设计该类,为什么?(不必,类的使用者可以根据具体要求

 

通过友元增加类的接口)

 

⑹使用友元要注意什么问题?(引入友元是人为地破坏了对象间的松耦合关系,削弱C++的封装和数据隐藏,可能导致程序的可维护

 

性和可读性较差,必须引起足够重视)