第十二章类和数据抽象12.1编写一个名为person的类,表示人的名字和地址,使用string来保存每个元素。答:classperson{public:person(stringpName,stringpAddress){name=pName;address=pAddress;}private:stringname;stringaddress;};12.2为person提供一个接收两个string参数的构造函数。见第一题。12.3提供返回名字和地址的操作。这些函数应为const吗?解释你的选择。在public里添加成员函数:stringget_name()const{returnname;]stringget_address()const{returnaddress;]这两个成员函数不应该修改其操作的对象的数据成员的值,应该声明为const类型。12.4指明person的哪个成员应声明为public,哪个成员应声明为private。解释。数据成员name和address应为private,保证只能被类的成员所用,外界不可访问。成员函数get_name()和get_address()应声明为public,为外界提供接口访问类的数据成员。构造函数也应声明为public,以便初始化类的对象。12.5C++类支持哪些访问标号?在每个访问标号之后应定义哪种成员?如果有的话,在类的定义中,一个访问标号可以出现在何处以及可出现多少次?约束条件是什么?有public,private,protect。public后定义可被外界访问的接口,private后定义只能被本类成员函数使用的成员;protect后定义的成员称为受保护成员,只能由本类及本类的子类访问。访问标号可以出现在任意成员定义之前且次数没有限制。约束条件是:每个访问标号指定了随后的成员定义级别,这个级别持续有效,直到下一个访问标号出现,或者看到类定义体的右花括号为止。12.6用class关键字定义的类和用struct定义的类有什么不同。默认访问标号不同,用struct关键字定义的,在第一个访问标号之前的成员是共有的,如果是用class关键字定义的,在第一个访问标号之前的成员是private成员。12.7什么事封装?为什么封装是有用的?封装是一种将低层次的元素组合起来形成新的、高层次实体的技术。例如,函数是封装的一种形式:函数所执行的细节行为被封装在函数本身这个更大的实体中。被封装的元素隐藏了它们的实现细节,可以调用一个函数但不能访问它所执行的语句,同样类也是一个封装的实体:它代表若干成员的聚集,大多数类类型隐藏了实现该类型的成员。封装隐藏了内部元素的实现细节,提供了优点:避免类内部出现无意的可能破坏对象状态的用户级错误;在修改类的实现时不需要修改用户级代码,这些都很有用。12.8将sales_item::avg_price定义为内联函数。inlinedoublesales_item::avr_price()const{if(units_sole)returnrevenue/units_sold;elsereturn0;}12.9修改本节中给出的screen类,给出一个构造函数,根据屏幕的高度、宽度和内容的值来创建screen。classScreen{public:typedefstd::string::size_typeindex;Screen(indexhei,indexwid,stringcontent){contents=content;height=hei;width=wid;}private:std::stringcontents;indexcursor;indexheight,width;};12.10解释下述类中的每个成员:classRecord{typedefstd::size_tsize;Record():byte_count(0){}Record(sizes):byte_count(s){}Record(std::stirngs):name(s),byte_count(0){}sizebyte_count;std::stringname;public:sizeget_count()const{returnbyte_count;}std::stringget_name()const{returnname;}};三个Record()函数是重载的三个构造函数,sizebyte_count;std::stringname;这是两个private的数据成员,sizeget_count()const,std::stringget_name()const这是两个public成员函数。12.11定义两个类X和Y,X中有一个指向Y的指针,Y中有一个X类型的对象。classY;classX{Y*p;};classY{Xxobj;};12.12解释类声明与类定义之间的差异。何时使用类声明?何时使用类定义?类声明是不完全类型,只能以有限方式使用,不能定义该类型的对象,只能用于定义指向该类型的指针及引用,或者声明使用该类型作为形参类型或返回类型的函数。类定义,一旦类被定义,我们就可以知道所有类的成员,以及存储该类的对象所需的存储空间。在创建类的对象之前或者使用引用或指针访问类的成员之前必须定义类。12.13扩展screen类以及包含move.set和display操作。通过执行如下表达式来测试类:myScreen.move(4,0).set(‘#’).display(cout);//12.13_Screen.cpp:定义控制台应用程序的入口点。//#includestdafx.h#includeiostream#includestringusingnamespacestd;classScreen{public:typedefstd::string::size_typeindex;Screen(indexhei,indexwid,conststring&content=){cursor=0;contents=content;height=hei;width=wid;}//add3newmembersScreen&move(indexr,indexc){indexrow=r*width;cursor=row+c;return*this;}Screen&set(charc){contents[cursor]=c;return*this;}Screen&display(ostream&os){do_display(os);return*this;}constScreen&display(ostream&os)const{do_display(os);return*this;}private:std::stringcontents;indexcursor;indexheight,width;voiddo_display(ostream&os)const{oscontents;}};int_tmain(intargc,_TCHAR*argv[]){Screenmyscreen(5,5,bbbbbbbbbb\ngggg\nfffffff\niiiiiiiiiiiiiiiiii\nmmmmmmmm\n);myscreen.move(4,0).set('#').display(cout);system(pause);return0;}12.14通过this指针引用成员虽然合法,但却是多余的。讨论显示地使用this指针访问成员的优缺点。优点:当需要将一个对象作为整体引用而不是引用对象的一个成员时,使用this,则该函数返回对调用该函数的对象的引用。可以非常明确地指出访问的是调用该函数的对象的成员,且可以在成员函数中使用与数据成员同名的形参。缺点:不必要使用,代码多余。12.15列出在类作用域中的程序文本部分。类的定义体;在类外定义的成员函数:形参表、成员函数体,但不包含函数的返回类型。12.16如果定义get_cursor时,将会发生什么?IndexScreen::get_cursor()const{returncursor;}编译错误,index是在Screen类的作用域之外的,在类外没有定义index类型。12.17如果将Screen类中的类型别名放到类中的最后一行,将会发生什么?发生编译错误,因为Index的使用出现在了其定义之前。12.18解释下述代码,指出每次使用Type或initVal时用到的是哪个名字定义。如果存在错误,说明如何改正。Typedefstringtype;TypeinitVal();classExercise{public://...typedefdoubleType;TypesetVal(Type);TypeinitVal();private:intval;};TypeExercise::setVal(Typeparm){val=parm+initVal();}成员函数setVal的定义有错。进行必要的修改以便类Exercise使用全局的类型别名Type和全局函数initVal.答:在类的定义体内,两个成员函数的返回类型和setVal的形参使用的Type都是类内部定义的类型别名Type;在类外的成员函数setVal的定义体内,形参的类型Type是Exercise类内定义的类型别名Type,返回类型的Type使用的是全局的类型别名Type。在steVal的定义体内使用的initVal函数,使用的是Exercise类的成员函数。在SetVal的函数定义有错:1.缺少返回类型;2.此函数的返回类型是string类型的,而类中声明的函数返回类型是double类型的,不合法的函数重载,可以改为:Exercise::TypeExercise::setVal(Typeparm){val=parm+initVal();returnval;}把setVal修改为如下,可保证类Exercise使用全局的类型别名Type和全局函数initVal.Typedefstringtype;TypeinitVal();classExercise{public://...TypesetVal(Type);private:Typeval;};TypeExercise::setVal(Typeparm){val=parm+initVal();returnval;}12.19提供一个或多个构造函数,允许该类的用户不指定数据成员的初始值或指定所有数据成员的初始值:classNoName{public://constructor(s)gohere...private:std::string*pstring;intival;doubledval;};解释如何确定需要多少个构造函数以及它们应该接受什么样的形参。实参决定调用哪个构造函数,所以实参的种类数决定构造函数的数目,因此此题至少需要两个构造函数,一个是默认没有参数的构造函数,一个是带有三个形参的构造函数,类型要与三个数据成员的类型匹配。构造函数:classNoName{public://constructor(s)gohere...NoName(){}NoName(std::string*ps,intiv,doubledv){pstring=ps;ival=iv;dval=dv;}private:std::string*pstring;intival;doubledval;};12.20从下述抽象中选择一个(或一个自己定义的抽象),确定类中需要什么数据,并提供适当的构造函数集。解释你的决定:(a)Book(b)Date(c)Employee(d)Vehicle(e)Object(f)Tree(b)Date:需要年:intyear;月:intmonth;日:intday构造两个构造函数,一个默认构造函数,用于创建空的Date对象,一个带有三个形参,用于创建指定日期的对象。构造函数为:classDate{public:Date(){}Date(in