《五章节类隐藏实现.ppt》由会员分享,可在线阅读,更多相关《五章节类隐藏实现.ppt(34页珍藏版)》请在三一办公上搜索。
1、第五章 类:隐藏实现,面向对象程序设计(C+),5.2 隐藏实现:例,内部电路(实现)有不同;但操作界面(接口)总是相同的。,5.2 隐藏实现:必要性,让库的使用者远离一些他们不需要知道的内部实现;允许库的设计者改变内部实现,而不必担心对客户程序员造成什么影响。,5.2 隐藏实现:原则,Public:turn_on();turn_off();volume_up();volume_down();change_channel();,private:change_red();change_blue();change_green();,boundary,将类的功能描述部分作为共有部分接口提供给用户;将
2、数据的内部表示、功能的内部实现作为私有部分 隐藏起来。,5.2.1 C+的访问控制,Public/private/protected Public:公有成员,其后声明的所有成员可以被 所有的人访问。Private:私有成员,除了该类型的创建者和类的 内部成员函数之外,任何人不能访问。Protected:保护成员,与Private基本相同,区别 是继承的结构可以访问Protected成员,但不可 以访问Private 成员。,int main()B b;b.i=1;/OK,public/!b.j=1;/illegal,/!b.f=1.0;/illegal,b.func();/OK,public/
3、:,注:protected修饰符将在后续章节解释,设置访问控制,struct B private:char j;float f;public:int i;void func();void B:func()B tempb;tempb.j=a;/OK i=0;j=0;f=0.0;,OOP的观点,访问控制在库的设计者(实现者)和库的使用者之 间划了一道明显的界线;j和f 需要保护;i和func()可以公开 若试图访问一个私有成员,就会产生一个编译 时错误。,5.2.2 友元,友元:显示地声明哪些人“可以访问我的私有实现 部分”。表明的是一种“信任”的关系。,struct Cfatherfriend
4、struct CMother;/赋予CMother访问/Cfather的salary的权利private:long salary;;struct CMotherpriavte:void inspect()Cfather obj_TaDie(8000);cout“月收入:”obj_TaDie.salary;,说明,友元不是类的成员,只是一个声明。友元可以是外部全局函数、类或类的成员函数;友元是一个“特权”函数,破坏了封装。当类的实 现发生变化后,友元也要跟着变动。,例:友元,/Friend allows special access/Declarationstruct X;/不完全的类型说明 s
5、truct Y void f(X*);struct X/Definitionprivate:int i;public:void initialize();friend void g(X*,int);/全局函数友元 friend struct Z;/类友元 friend void Y:f(X*);/成员函数友元,friend void h();/全局函数友元;void X:initialize()i=0;/类X的初始化函数void g(X*x,int i)x-i=i;/访问X的私有成员ivoid Y:f(X*x)x-i=47;/访问X的私有成员i,void h()X x;x.i=100;/直接访
6、问私有成员int main()X x;Z z;z.g(/:,struct Z private:int j;public:void initialize();void g(X*x);void Z:initialize()j=99;void Z:g(X*x)x-i+=j;,OOP的视点,友员不是OOP的特征,破坏了封装性,这也是C+不是“纯”面向对象语言的原因之一。,5.2.3 从struct到class,封装:数据成员+成员函数 抽象数据类型访问控制:接口与实现的分离 C的struct+封装+访问控制=类(Class),思考:CStash和CStack中,哪些成员应该设置为私有的?哪些成员应该设
7、置为公有的?,例1:带访问控制的类Stash,class Stash private:int size;/Size of each space int quantity;/Number of storage spaces int next;/Next empty space unsigned char*storage;void inflate(int increase);public:void initialize(int size);void cleanup();int add(void*element);void*fetch(int index);int count();,例2:有访问控制
8、的类 Stack,#ifndef STACK2_H#define STACK2_Hclass Stack struct Link/私有的 void*data;Link*next;void initialize(void*dat,Link*nxt);*head;public:void initialize();void push(void*dat);void*peek();void*pop();void cleanup();#endif/STACK2_H/:,5.2.3.1 Class和Struct的区别,class X int i;/私有成员 int y;/私有成员 void f();/私有成
9、员,class的成员默认为Private;struct的成员默认为Public.,struct X int i;/公有成员 int y;/公有成员 void f();/公有成员,5.2.4 访问控制的一个陷阱,返回private数据成员的非const引用:当类的public成员函数f返回对该类private成员m的非const引用时,如果f的调用作为赋值语句的左值,则访问控制不起作用,对象的使用者可以直接存取m的值。称这种情形为访问控制的“陷阱”。,class Xprivate:int i;public:int/此时i的值为-20;,例1,例2,class Time public:Time(i
10、nt=0,int=0,int=0);void setTime(int,int,int);int getHour();int,#include time4.h#include Time:Time(int hr,int min,int sec)setTime(hr,min,sec);void Time:setTime(int h,int m,int s)hour=(h=0,/Fig.6.11:time4.cpp,/极其危险的做法:/Returning a reference to a private data member.int/DANGEROUS reference return,#inclu
11、de#include time4.hint main()Time t;int,/Fig.6.11:fig06_11.cpp,cout Hour before modification:hourRef;hourRef=30;/modification with invalid value cout nHour after modification:t.getHour();/Dangerous:Function call that returns/a reference can be used as an lvalue!t.badSetHour(12)=74;cout badSetHour as
12、an lvalue,Hour:t.getHour()n*endl;return 0;,20 30 74,如何填补这个陷阱?利用const!,#include#include class Ctest char*str;public:Ctest(int sz)str=new charsz;strcpy(str,ustc is a famouse uni.);Ctest()delete str;char const*getstr()const return str;;,例3:返回char*,int main(int argc,char*argv)Ctest t1(100);strcpy(t1.get
13、str(),“TEST!);/ERROR cout t1.getstr();return 0;,编译时错误:can not convert“const char*”to“char*”,5.2.6 句柄类,尽管客户程序员(类的使用者)不能访问私有实现部分,然而由于必须给他们提供.h文件,他们可以轻易地“看到”类是如何实现的。-如何使得他们“看不见”实现?如果改变了类的实现,即使没有改变类的接口,也可能需要重新编译所有使用了该类的客户程序。-如何尽可能地避免不必要的重复编译。,类的实现者的烦恼:,解决办法:利用“句柄类”。所谓句柄类,是一个特殊的类,该类中含有一个特殊的成员-一个指向被隐藏的类的指
14、针;,接口:公开的部分(Handle.h),/Handle classes#ifndef HANDLE_H#define HANDLE_Hclass Handle struct Cheshire;/类cheshire的声明;Cheshire*smile;/smile 指针指向具体的实现public:void initialize();void cleanup();int read();void change(int);#endif/HANDLE_H/:,编译器从以上定义完全知道如何安排类Handle的存储,因此Handle无需知道Cheshire的具体实现,从而达到隐藏实现的目的。,void
15、Handle:cleanup()delete smile;int Handle:read()return smile-i;void Handle:change(int x)smile-i=x;/:,实现:需要隐藏的部分(Handle.cpp),/Handle implementation#include Handle.h#include./require.h/句柄类的实现:cheshirestruct Handle:Cheshire int i;void Handle:initialize()smile=new Cheshire;smile-i=0;,优点,由于实现部分并没有暴露在.h中,保密性好;因为实现的细节均隐藏在句柄类的背后,因此 当实现发生变化时,句柄类并没有改变,也就 不必重新编译客户程序,只需重新编译隐藏的 实现这一小部分代码,然后连接(link)就行了。减少了大量的重复编译。,小结,访问控制:public/private/protected 友元:friend 访问控制的陷阱:返回private数据成员的非 const引用 句柄类:隐藏实现源代码,两方面的优点,作业:,P279(中文版P144)5.1,5.5 5.13(上机)补充题:创建Cfather,Cmother类,包括姓名、年龄、月薪等属性,另外爸爸会打网球,妈妈会织毛衣。按你自己的喜好设置访问控制。,