您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 公司方案 > 第四章C++语言中的类数据类型
习题、思考题与上机试验题:⒈试判断下列命题的对错:·C++语言中的struct是只有public区的class。·在class中如果不定义缺省构造函数,则该class的缺省构造函数便不存在。·只要包含有private区的的类便具有封装特性。·类的常数型成员只能用成员初始化表的手段初始赋值。·delete语句可以删除任何对象。·如果类内含有静态成员,则类的对象不会有静态成员的拷贝。⒉若要在例3中增加一修改函数但又不允许类外使用,则这个函数应在何处定义?⒋能不能在例4中的main()函数内直接调change())呢?请思考后上机试验。⒌若用C语言完成例5的运算并将其作用域算符取消会产生何种效果呢?请上机试验观察。⒎例11中r指向i后还能在运行时改变指向吗?请上机试验证。⒏this指针不能用于对静态成员(数据或函数)的操作或访问,为什么?⒐例19内的函数gn()中this-p-name是属于哪个对象的?返回后所显示的内容是什么?第四章C++语言中的类数据类型在所有的C++语言的最基本的概念中,类(class)便是核心。读者若已系统地学习过面向对象的分析与程序设计方法,相信学习本章的内容将不会有很大的困难。在掌握了本章论述的C++语言的最基本的概念之后,再回头重温面向对象的程序设计方法便会更深刻地体会其精深之处了。§1类的数据封装在给出类的定义前先回顾一下C++中的struct的声明过程。§1.1C++语言中的结构数据类型相对于C语言的变化在C语言中,struct声明一般是同对其操作的程序代码相分离的。这种声明上的分离带来了两个弊端。一是软件维护人员(不一定是设计人)不知道对其操作的函数叫什么?在何处?有多少个?二是一旦修改struct内的成员,对应程序也必需跟着修改。但这容易造成程序设计人员的疏漏。对此C++语言作出了质的修改。C++语言允许将对该结构内的数据成员进行操作的函数也作为其成员在struct内予以声明。例1:#includeiostream.hstructDt{unsignedintyy,mm,dd;voiddsp(){coutyy’.’mm’.’dd\n;}};voidmain(){Dtd;d.dsp();}请读者注意例1中main()引用Dt的成员函数dsp()的书写格式与引用其数据成员数据的书写格式完全一致。C++语言的struct正是后面要讲的class声明的一个特例,类的概念也由此引出。在以后的章节中,还将多次引用这一概念。要强调的另一点是在C++语言中含有成员函数原形声明的struct必须做为全局结构安排。因为C++不支持局部函数嵌套的声明结构。§1.2C++语言中的类在例1中声明了一个“structDt”的数据结构,随后又以“Dt”直接去定义一个对象“d”。此时的“Dt”已如同int,char等数据类型符号一样成了另一种数据类型的定义符号。深究一下又可以说这个“Dt”是一个用户自定义的一个新类型。这和在C语言中用typedef来定义除struct、union之外的各种类型符号不同的是“Dt”中的结构完全是由程序员安排的,而typedef产生的符号只能是一个已知的类型符号的派生(Derived)形式。例中的struct不仅有成员数据而且还包含成员函数,它就是C++语言中的一个类的特例。由此推论,C++语言中的类实际上是一种由用户自定义的数据结构的广义数据类型,它不仅包括有一组结构数据成员而且包括将对这些数据成员进行操作的专用的成员函数。后者是C语言的结构类型中所不允许的。在C++语言中的struct虽然也允许插入成员函数,但其内特性与后面即将论述的“class”有着质的不同,至多可以看做是向“class”的过渡。类作为自定义的数据结构只是一种抽象的描述。按照面向对象的分析理论,类还具有定义其实体—对象的能力。在C++语言中,用类定义对象的过程就是按照类所需的容量,动态占用内存资源、复制类中的全部数据结构并向其内部注入各项初始的数值。类在编程书写时用一个“class”的保留字声明,类名惯用大写字母开头,其格式是:格式一:class类名{成员名字定义表}[对象名表];格式二:class已声明的类名对象名表;格式三:class已声明的类名;格式一是用来实现类声明的。也可以通过跟在其后的对象名表同时声明该类的一至多个对象。格式二是用已声明好的类名来定义对象(object)的。格式三是类的引用声明,用于类间引用场合(即先声明后引用)。格式一的成员名表的结构如下:public:成员声明区private:成员声明区protected:成员声明区这里public、private和protected同class一样都是C++语言的保留字。在一个class的最前端,如不指明区名则缺省区名为private。成员声明区内各种成员数据的书写格式与struct内的成员数据书写格式一样。与之发生操作关系的成员函数只能对声明在同一class内的成员数据进行操作。§1.3类的三个区一个class中的三个区public(公有区)、private(专有区)和protected(保护区)分别对声明于各区中的成员附加了三种不同的属性。由于protected区与类的派生有极密切的关系,故将其内容合并到第六章论述。一.public区属性凡声明在该区中的所有成员,当本类对象生成后可以被类外的全局程序或其它类中的成员函数直接访问。例2:#includeiostream.hclassDay{public:unsignedintmm,dd,yy;voiddateset(unsignedintm=1,unsignedintd=1,unsignedinty=1){mm=m;dd=d;yy=y;}};voidmain(){Daydt;dt.dateset();cout”Date:”dt.yy’.’dt.mm’.’dt.dd”\n”;}/*main函数访问dt的函数的数据*/二.private区属性凡声明在该区内的所有成员,当本类对象生成后只能被本类的成员函数直接访问。类外的全局程序则要通过一个定义在public区内的成员函数为媒介间接访问。如在例2中要想看到日期值就必须在public区内安排一显示函数(如dsp())来实现了。§1.4数据的封装仔细分析一下class的结构,便会发现private区就如同一个黑盒子。类外的全局程序不能直接访问而对类内的成员却完全透明。其形象可由下图表现出来:InputWindow→public→OutputWindow↓↑class外部全局数据区private图4-1图中示意的窗口为class对外的信息交换通道。可归纳为下述的两个基本特点:①class中必须有public区以作为class对外的接口。否则class的对象无法与外界实现数据交换。②class中必须有private区以使class内的部分或全部成员可以被封装在其内而不易受到外界的影响。此时再来看图4-l如同一块集成电路芯片,框内是芯片的内部工作流程,而Window则如同芯片上的管脚(Pin)。一个class就好像是制造芯片的模具,可以定义出许多具有完全相同内部工作流程和外部管脚排列的具体芯片来。因此,在C++语言中的class恰是面向对象理论中的数据封装。但要强调指出的是一个类对象内只有类数据结构的拷贝,但并没有成员函数的拷贝。当一个类对象诞生时,其内部仅有一张指向类的所有成员函数的地址和状态表,以供运行之需。class的数据封装特性只是相对于类外世界的,而对同类的不同对象却不起作用。因此,一个类对象可以通过引用本类的某个成员函数去访问位于另一个同类对象中任何区内的成员数据。当回过头再审视一下例1中的struct,若在其中也插人一些函数是否可以形成数据封装呢?显然它不满足刚提到的特点②,即数据不能隐藏(DataHidden),也就是说struct之外的程序依然可以自如地对struct内所定义的数据和函数实施访问。所以只能说它是一个类的特例(无private区)而不是数据封装。例3:#includeiostream.hclassST{charname[10];unsignedintnum,cnum;public:voidinit(){cout”\nPleaseinputthedataofstudent:\nNAME:”;cinname;cout”NUMBER:”;cinnum;cout”CLASSNUMBER:”;cincnum;}voiddsp(){cout”NAME:”name”\nNUMBER:”num”\nCLASS:”cnum;}};voidmain(){STs1;s1.init();s1.dsp();}例3是一个简单的学生档案处理系统,类ST中只定义了两个成员函数用于对学生数据的初始化和显示。例4:#includeiostream.hclassCount{characcount_num[10];intaccount_value;intchange(){intval;cout”Pleaseinputthevalue:”;cinval;if(val=account_value){account_value=account-val;returnaccount_value;}else{cout”Overflow!!NotChange!\n”;return0;}}public:voidinit(inti){account_value=i;}voidaccount_chk(){cout”Pleaseinputtheaccountnumber:“;cinaccount_num;cout”Takevalue:”change()”\n”;}};voidmain(){Countct;ct.init(10000);ct.account_chk();ct.account_chk();ct.account_chk();}例4设想在一个银行中用作取款操作(为节省篇幅而有意取捎了账号查验函数)。要强调的是为了使用户数据不被类外程序伤害,连同修改函数都放在了private区内定义。这样使用时必须通过接口函数account_chk()才能修改,同时也只有这一种流程。§1.3类中成员函数的一些特性。若注意前面的几个例子后会发现定义在class中的成员函数的声明与定义是在一起的。根据前一章的论述,本应将其声明与定义分离,这里何以又集中了呢?根本原因在于若在类中将声明与定义合二为一,则成员函数便被编译器自动地认定为内联函数(inlinefunction)。如果分离,则要在函数的前面插入“inline”关继字才能成为内联函数。一般地声明与定义合二为一的函数都比较短小,结构也很简单(通常不包含循环),反之就应当分离。由于C++语言中每个类成员函数都是有其所属的类作用域范围的,声明与定义分开后则必须在类外再对成员函数进行定义。此时要使用一个称为类作用域算符“∷”的特殊符号来表明函数的归属。则类成员函数在类外的通用定义格式为:返回值类型类名∷函数名(参数表){过程语句}如:classA{…public:intinit(int);…};intA::init(inti){…}若要定义函数为内联的话,可前缀“inline”关键字,则上一行可写成:inlineintA::init(inti){…}实际上,类作用域算符不仅仅用于对类成员函数(包括成员数据)的定义,还可以用于struct和非类属的全局程序作用域中。若在全局(Global)数据区中定义了与在某函数的局部(Local)数据区中相同的变量名,则程序以局部优先的原则总是先访问当前函数内的局部变量。而在C++语言中,不同位置的程序可以通过类作用域算符来访问不同作用域的变量(当然首先应有权访问)。当程序要访问全局数据区中的变量时,只要在变量名前缀以一个“∷”符号即可。例5:#includestdi
本文标题:第四章C++语言中的类数据类型
链接地址:https://www.777doc.com/doc-2167599 .html