第十五章 面向对象编程.docx
《第十五章 面向对象编程.docx》由会员分享,可在线阅读,更多相关《第十五章 面向对象编程.docx(43页珍藏版)》请在冰豆网上搜索。
第十五章面向对象编程
第十五章面向对象编程
1。
什么是虚成员?
在类中被声明为virtual的成员,基类希望这种成员在派生类中重定义。
除了构造函数外,任意非static成员都可以为虚成员。
2。
给出protected访问标号的定义。
它与private有何不同?
protected为受保护的访问标号,protected成员可以被该类的成员、友元和派生类成员(非友元)访问,而不可以被该类型的普通用户访问。
而private成员,只能被基类的成员和友元访问,派生类不能访问。
3。
定义自己的Item_base类版本。
classItem_base
{
public:
Item_base(conststring&book='',doublesales_price=0.0):
isbn(book),price(sales_price){}
stringbook()const
{
returnisbn;
}
virtualdoublenet_price(size_tn)const
{
returnprice*n;
}
virtual~Item_base(){}
private:
stringisbn;
protected:
doubleprice;
};
4。
图书馆可以借阅不同种类的资料—书、CD、DVD等等。
不同种类的借阅资料有不同的登记、检查和过期规则。
下面的类定义了这个应用程序可以使用的基类。
指出在所有借阅资料中,哪些函数可能定义为虚函数,如果有,哪些函数可能是公共的。
(注:
假定LibMember是表示图书馆读者的类,Date是表示特定年份的日历日期的类。
)
classLibrary
{
public:
boolcheck_out(constLibMember&);
boolcheck_in(cosntLibMember&);
boolis_late(constDate&today);
doubleapply_fine();
ostream&print(ostream&=count);
Datedue_date()const;
Datedate_borrowed()const;
stringtitle()const;
constLibMember&member()const;
};
因为有不同的登记、检查、和过期规则,所以
boolcheck_out(constLibMember&);
boolcheck_in(cosntLibMember&);
boolis_late(constDate&today);
doubleapply_fine();
ostream&print(ostream&=count);
这几个函数应该被定义为虚函数,print函数可能用于打印不同的项目的内同,也定义为虚函数。
其他几个函数,因为操作都有公共性质,所以应该是公共的。
5。
如果有,下面的声明中哪些是错误的?
classBase{…};
(a)classDerived:
publicDerived{…};
(b)classDerived:
Base{…};
(c)classDerived:
PrivateBase{…};
(d)classDerived:
publicBase;
(e)classDerived:
inheritsBase{…};
(a)错误,不能用类本身作为类的基类,(d)声明类时,不可以包含派生列表。
(e)派生不能用inherits
6。
编写自己的Bulk_item类版本。
classBulk_item:
publicitem_base
{
public:
doublenet_price(size_tcnt)const
{
if(cnt>min_qty)
returncnt*(1-discount)*price;
else
returncnt*price;
}
private:
size_tmin_qty;
doublediscount;
};
7。
可以定义一个类型实现有限折扣策略。
这个类可以给低于某个上限的购书量一个折扣,如果购买的数量超过该上限,则超出部分的书应按正常价格购买。
定义一个类实现这种策略。
classLtd_item:
publicitem_base
{
public:
Ltd_item(conststring&book=“”,doublesales_price,size_tqty=0,doubledisc_rate=0):
item_base(book,sales_price),max_qty(qty),discount(disc_rate){}
doublenet_price(size_tcnt)const
{
if(cnt<=max_qty)
returncnt*(1-discount)*price;
else
returncnt*price–max_qty*discount*price;
}
private:
size_tmax_qty;
doublediscount;
};
8。
对于下面的类,解释每个函数:
structbase
{
stringname(){returnbasename;}//返回私有成员basename
virtualvoidprint(ostream&os){os<private:
stringbasename;
};
structderived
{
voidprint(){print(ostream&os);os<<““<private:
intmem;
};
如果该代码有问题,如何修正?
问题:
没有声明类derived是从base派生过来的,改正为如下:
structbase
{
base(stringszNm):
basename(szNm){}
stringname(){returnbasename;}//返回私有成员basename
virtualvoidprint(ostream&os){os<private:
stringbasename;
};
structderived:
publicbase
{
derived(stringszName,intiVal):
base(szName),mem(iVal)()
voidprint(){print(base:
:
ostream&os);os<<““<private:
intmem;
};
9。
给定上题中的类和如下对象,确定在运行时调用哪个函数:
basebobj;base*bp1=&base;base&br1=bobj;
deriveddobj;base*bp2=&doboj;base&br2=dobj;
(a)bobj.print();
(b)dobj.print();
(c)bp1->name();
(d)pb2->name();
(b)br1.print();
(f)br2.print();
(a)bobj.print();用的是基类的print函数
(b)dobj.print();用的是派生类的print函数
(c)bp1->name();用的是基类的name函数
(d)pb2->name();用的是基类的name函数
(b)br1.print();用的是基类的print函数
(f)br2.print();用的是派生类的print函数
10。
在15.2.1节的习题中编写一个表示图书馆借阅政策的基类。
假定图书馆提供下列种类的借阅资料,每一种有自己的检查和登记政策。
将这些项目组成一个继承层次:
bookatdiobookrecord
children’spuppetsegavideogamevideo
cdrombookNintendovideogamerentalbook
sonyplaystationvideogame
类book、record、children’spuppet、video继承自Library;
类audiobook,cdrombook,rentalbook继承自类book;
类segavideogame,Nintendovideogame,sonyplaystationvideogame继承自类video.
11。
在下列包含一族类型的一般抽象中选择一种(或者自己选择一个),将这些类型组织成一个继承层次。
(a)图像文件格式(如gif,tiff,jpeg,bmp)
(b)几何图元(如矩形,圆,球形,锥形)
(c)C++语言的类型(如类,函数,成员函数)
对(b)中的几何图元组织成一个继承层次,
基类Figure,
矩形Rectangle,圆cicle,球形sphere,锥形Cone继承自Figure类。
12。
对上题中选择的类,标出可能的虚函数以及public和protected成员。
虚函数,比如计算图形面积的函数virtualdoublearea();计算体积的函数virtualdoublecubage();求周长的函数virtualdoubleperimeter();
Figuer类的public成员可能有两个图元的尺寸:
xSize,ySize,其他类的protected成员可能有cone类和球形的zSize即Z轴尺寸,还有
13。
对于下面的类,列出C1中的成员函数访问ConcreteBase的static成员的所有方式,列出C2类型的对象访问这些成员的所有方式。
structConcreteBase
{
staticstd:
:
size_tobject_count();
protected:
staticstd:
:
size_tobj_count;
};
structC1:
publicConcreteBase{//…}
structC2:
publicConcreteBase{//…}
C1中的成员函数访问基类的static成员可以用
(1)ConcreteBase:
:
成员名
(2)C1:
:
成员名
(3)通过C1类对象或对象的引用,使用(.)操作符访问
(4)通过C1类对象的指针,使用箭头(->)操作符访问
(5)直接使用成员名。
C2类型的对象访问时,只可以访问基类的成员函数,假如C2对象为obj_c2,可用
(1)obj_c2.object_count()
(2)ConcreteBase:
:
object_count()
(3)C2:
:
pbject_count()
14。
重新定义Bulk_item和item_base类,使每个类只需定义一个构造函数。
classItem_base
{
public:
Item_base(conststring&book=“”,doublesales_price=0.0):
isbn(book),price(sales_price){}
stringbook()const
{
returnisbn;
}
virtualdoublenet_price(size_tn)const
{
returnprice*n;
}
virtual~Item_base(){}
private:
stringisbn;
protected:
doubleprice;
};
classBulk_item:
publicItem_base
{
public:
Bulk_item(conststring&book=“”,doublesales_price=0.0,
size_tqty=0,doubledisc=0.0):
Item_base(book,sales_price),min_qty(qty),discount(disc){}
doublenet_price(size_tcnt)const
{
if(cnt>min_qty)
returncnt*(1-discount)*price;
else
returncnt*price;
}
private:
size_tmin_qty;
doublediscount;
};
15。
对于15.2.5节第一个习题中描述的图书馆类层次,识别基类和派生类构造函数。
基类为IS_A结构中的上边的类为下边的类的基类,派生类构造函数应在初始化列表中包含其直接基类以初始化继承成员和派生类自己的成员。
16。
对于下面的基类定义:
(a)没有在初始化列表中向基类构造函数传递实参,
(b)初始化列表中出现了非直接基类Base,
(c)初始化列表中出现了非直接基类Base,而没有出现直接基类C1,
(d)初始化列表中使用了未定义变量id
(e)缺少了初始化列表,基类没有默认构造函数,其派生类必须用初始化列表对基类的构造函数传递实参。
17。
说明在什么情况下类应该具有虚析构函数。
作为基类使用的类应该具有虚析构函数,以保证在删除指向动态分配对象的基类指针时,根据指针实际指向的对象所属的类型运行适当的析构函数。
18。
虚析构函数必须执行什么操作?
虚析构函数可以为空,即不执行任何操作,而当类中有指针类成员时,则需要自己定义虚析构函数,以对指针成员进行适当的清除。
19。
如果这个类定义有错,可能是什么错?
可能是因为该类可能作为基类使用,所以这时必须定义虚析构函数。
而这个类没有定义虚析构函数。
20。
回忆在13.3节习题中编写的类,该类的复制控制成员打印一条消息,为Item_base和Bulk_item类的构造函数增加打印语句,定义复制控制成员,使之完成与合成版本相同的工作外,还打印一条消息,应用使用了Item_base类型的那些对象和函数编写一些程序,在每种情况下,预测将会创建和撤销什么对象,并将你的预测与程序所产生的结果进行比较。
继续实验,直至你能够正确地预测对于给定的代码片段,会执行哪些复制控制成员。
#include
#include
#include
usingnamespacestd;
classItem_base
{
public:
Item_base(conststring&book="",doublesales_price=0.0):
isbn(book),price(sales_price)
{
cout<<"UsingItem_base'sconstructor."<}
stringbook()const
{
returnisbn;
}
virtualdoublenet_price(size_tn)const
{
returnprice*n;
}
virtual~Item_base()
{
cout<<"UsingItem_base'sdestructor."<system("pause");
}
friendostream&operator<<(ostream&,Item_base&);
private:
stringisbn;
protected:
doubleprice;
};
ostream&
operator<<(ostream&os,Item_base&ib)
{
os<<"\tUsingoperator<<(ostream&,Item_base&);"<<<"\tVisitItem_base'sbook():
\t"<<<"\tVisitItem_base'snet_price():
"
<<"\t3《"<\t"<<_price(3)<returnos;
}
classBulk_item:
publicItem_base
{
public:
Bulk_item(conststring&book="",doublesales_price=0.0,
size_tqty=0,doubledisc=0.0):
Item_base(book,sales_price),min_qty(qty),discount(disc)
{
cout<<"UsingBulk_item'sconstructor."<}
doublenet_price(size_tcnt)const
{
if(cnt>min_qty)
returncnt*(1-discount)*price;
else
returncnt*price;
}
~Bulk_item()
{
cout<<"UsingBulk_item'sdestructor."<system("pause");
}
private:
size_tmin_qty;
doublediscount;
};
ostream&
operator<<(ostream&os,Bulk_item&bi)
{
os<<"\tUsingoperator<<(ostream&,Bulk_item&)"<<<"\tVisitBulk_item'sbook():
\t"<<<"\tVisitBulk_item'snet_price():
"
<<"\t5《"<\t"<returnos;
}
int_tmain(intargc,_TCHAR*argv[])
{
Item_basebase("C++Primer",42.00);
Bulk_itembulk("Howtoprogram",50.32,3,0.2);
cout<
cout<system("pause");
return0;
}
21。
重新定义Item_base层次以包含Disc_item类。
classItem_base
{
public:
Item_base(conststring&book=“”,doublesales_price=0.0):
isbn(book),price(sales_price){}
stringbook()const
{
returnisbn;
}
virtualdoublenet_price(size_tn)const
{
returnprice*n;
}
virtual~Item_base(){}
private:
stringisbn;
protected:
doubleprice;
};
classDisc_item:
publicItem_base
{
public:
Disc_item(conststring&book=“”,doublesales_price=0.0,
size_tqty=0,doubledisc=0.0):
Item_base(book,sales_price),quantity(qty),dicount(disc){}
doublenet_price(size_tcnt)
{
if(cnt>=quantity)
returncnt*(1-discount)*price;
else
returncnt*price;
}
std:
:
pairdiscount_policy()const
{returnstd:
:
make_pair(quantity,discount);}
protected:
size_tquantity;
doublediscount;
};
22。
重新定义Bulk_base和习题15.2.3节中实现的那个表示有限折扣策略的类,继承含Disc_item类。
classDisc_item:
publicItem_base
{
public:
Disc_item(conststring&book=“”,doublesales_price=0.0,
size_tqty=0,doubledisc=0.0):
Item_base(book,sales_price),quantity(qty),discount(disc){}
doublenet_price(size_tcnt)
{
if(cnt>=quantity)
returncnt*(1-discount)