《C++ Primer》和《C++c primer plus 区别》有哪些区别

《c++primer》第15章面对对象程序设计习题解答
《c++primer》第15章面对对象程序设计习题解答
[摘要:训练15.1:甚么是实成员? 正在类中声明为virtual的成员函数,基类愿望这类成员函数正在派死类中被从新界说。除组织函数不克不及被界说为实成员函数为,其他的肆意非static成员函数能够定]
练习15.1:什么是虚成员?
在类中声明为virtual的成员函数,基类希望这种成员函数在派生类中被重新定义。除了构造函数不能被定义为虚成员函数为,其他的任意非static成员函数可以定义为虚成员函数(也就是说析构函数可以定义为虚成员函数)
练习15.2:protected访问说明符与private有何区别?
protected是受保护的访问说明符,意味着被protected声明的成员可以被该类的成员、友元以及该类的派生类成员(非友元)访问,但不能被该类的对象访问。
而private声明的成员,只能被该类的成员和友元访问,该类的派生类不能访问。
练习15.3:定义你自己的Quote类和print_total函数。
class Quote { public:
Quote(const std::string &book,double sales_price):
bookNo(book),price(sales_price){}
std::string isbn() const {return bookNo;}
virtual double net_price(std::size_t n)const {return n*} //返回给定数量的书籍的销售总额,派生类改写并使用不同的折扣计算方法
virtual ~Quote()=
//对析构函数进行动态绑定 private:
std::string bookNo;
//书籍的ISBN编号 protected:
double price=0.0;
//代表普通状态下不打折的价格 };
注:此类为书上定义的Quote类。
练习15.4:下面哪条声明语句是不正确的?请说明原因。
class Base {
}; (a) class Derived : public Derived { … }; (b) class Derived : private Base
{ … }; (c) class Derived : public B
(a)不正确,一个类本身不能从自己派生而来
(c)不正确,声明类的时候,不可以包含派生列表,只有在定义类的时候才派生列表。
练习15.5:定义你自己的Bulk_quote类
class Bulk_quote : public Quote { public:
double net_price( size_t cnt ) const override
if ( cnt &=min_qty )
return cnt * ( 1- discount ) *
return cnt *
size_t min_
练习15.6:将Quote类和Bulk_quote的对象传给15.2.1节(第529页)练习中的print_total函数,检查该函数是否正确。
练习15.7:定义一个类使其实现一种数量受限的折扣策略,具体策略是:当购买书籍的数量不超过一个给定的限量时享受折扣,如果购买量一旦超过了限量,则超出的部分将以原价销售。
class Limited_quote : public Quote { public:
double net_price( size_t cnt ) const override
if ( cnt &=min_qty )
return cnt * ( 1- discount ) *
return min_qty*(1-discount)*price+(cnt-min_qty) *
size_t min_
练习15.8:给出静态类型和动态类型的定义。
静态类型在编译时就已经确定了,它是变量声明时的类型或表达式生成的类型;而动态类型则是变量或表达式表示的内存中的对象的类型,动态类型直到运行时才能知道。
Quote *pQuote =new Bulk_
指针pQuote的静态类型是Quote,在编译时就已经确定了。但是它的动态类型是Bulk_quote,直到运行时才能知道它指向的是基类还是派生类。
如果一个变量非指针也非引用,则它的静态类型和动态类型永远一致。但基类的指针或引用的动态类型可能与其动态类型不一致。
练习15.9:在什么情况下表达式的静态类型可能与动态类型不同?请给出三个静态类型与动态类型不同的例子。
Bulk_ Quote *pQuote=& Quote &rQuote=
只知道两个,第三个不知道,o(╯□╰)o
练习15.10:回忆我们在8.1节(第279页)进行的讨论,解释第284页中将ifstream传递给Sales_data的read函数的程序是如何工作的。
在要求使用基类型对象的地方,可以使用派生类型的对象来代替。
练习15.11:为你的Quote类体系添加一个名为debug的虚函数,令其分别显示每个类的数据成员。
#include &iostream& class Quote { public:
Quote(const std::string &book,double sales_price):
bookNo(book),price(sales_price){}
std::string isbn() const {return bookNo;}
virtual double net_price(std::size_t n)const {return n*} //返回给定数量的书籍的销售总额,派生类改写并使用不同的折扣计算方法
virtual void debug()
cout&&&bookNo=&&&bookNo&&& price=&&&price&&
virtual ~Quote()=
//对析构函数进行动态绑定 private:
std::string bookNo;
//书籍的ISBN编号 protected:
double price=0.0;
//代表普通状态下不打折的价格
class Bulk_quote : public Quote {
Bulk_quote(const string &book=&&,double sales_price=0,size_t qty=0,double disc_rate=0):
Quote(book,sales_price),min_qty(qty),discount(disc_rate) { }
double net_price( size_t cnt ) const
if ( cnt & min_qty )
return cnt * ( 1- discount ) *
return cnt *
virtual void debug()
Quote::debug();
//bookNo变量为private,所以我们不能直接访问bookNo,只能调用基类的debug()函数来显示
cout&&&min_qty=&&&min_qty&&& discount=&&&discount&&
size_t min_
}; int main(int argc, const char * argv[]) {
Quote base(&0-201-);
Bulk_quote derived(&0-201-,5,0.19);
base.debug();
derived.debug();
return 0; }
输出结果为:
bookNo=0-201-82470-1 price=50 bookNo=0-201-82470-1 price=50 min_qty=5 discount=0.19
练习15.12有必要将一个成员函数同时声明成override和final吗?为什么?
override:在C++11新标准中我们可以使用override关键字来说明派生类中的虚函数。这么做的好处是在使得我们的意图更加的清晰即明确的告诉编译器我们想要覆盖掉已存在的虚函数。如果我们定义了一个函数与基类中的名字相同但是形参列表不同,在不使用override关键字的时候这种函数定义是合法的,在使用了override关键字之后这种行为是非法的,编译器会提示出错。
final:如果我们将某个函数定义成final,则不允许后续的派生类来覆盖这个函数,否则会报错。
因此同时将一个成员函数声明成override和final能够使我们的意图更加清晰。
练习15.13给定下面的类,解释每个print函数的机理:
class base { public:
string name() { }
virtual void print( ostream &os ) { os &&
} private:
}; class derived:public base { public:
virtual void print(ostream &os)
print(os);
} private:
base中的print函数打印出自己的base name,而derived类则调用base类的print()函数打印出private变量base name之后,再打印一个空格和自己的private变量i。
注:我在Xcode下实际发现,当derived类中的print()函数调用base类中的print()函数时,应当显示注明,即
#include &iostream& class base { public:
base(string name):basename(name){}
string name() { }
virtual void print( ostream &os ) { os &&
} private:
}; class derived:public base { public:
derived(string name,int val):base(name),i(val){}
virtual void print(ostream &os)
base::print(os);
//显示注明
} private:
}; int main() {
base b1(&base&);
derived d1(&derived&,5);
b1.print(cout);
d1.print(cout);
return 0; }
运行结果如图所示:
basederived
练习15.14给定上一题中的类以及下面这些对象,说明在运行时调用哪个函数:
&base *bp1 = && base&br1 =
base *bp2 = & base&br2 =
(a)&bobj.print();
(b)&dobj.print();
(c)&bp1-&name();
(d) bb2-&name();
(b)&br1.print();
(f)&br2.print();
(a)& bobj.print();&用的是基类的print函数
(b)& dobj.print();&用的是派生类的print函数
(c)& bp1-&name(); 用的是基类的name函数
(d) &bp2-&name(); 用的是基类的name函数
(b)& br1.print();&&用的是基类的print函数
(f)& br2.print();&&& 用的是派生类的print函数
练习15.15定义你自己的Disc_quote和Bulk_quote。
class Disc_quote:public Quote { public:
Disc_quote(const string &book=&&,double sales_price=0.0,size_t qty=0,double disc=0.0):Quote(book,sales_price),quantity(qty),discount(disc){}
double net_price(size_t cnt) const=0; protected:
class Bulk_quote : public Disc_quote {
Bulk_quote(const string &book=&&,double sales_price=0,size_t qty=0,double disc_rate=0):
Disc_quote(book,sales_price,qty,disc_rate) { }
double net_price( size_t cnt ) const
if ( cnt & quantity )
return cnt * ( 1- discount ) *
return cnt *
练习15.16改写你在15.2.2节(第533页)练习中编写的数量受限的折扣策略,令其继承Disc_quote。
class Limited_quote : public Disc_quote { public:
Limited_quote(const string &book=&&,double sales_price=0.0,size_t qty=0,double disc_rate=0.0):
Disc_quote(book,sales_price,qty,disc_rate) { }
double net_price( size_t cnt ) const override
if ( cnt &=quantity )
return cnt * ( 1- discount ) *
return quantity*(1-discount)*price+(cnt-quantity) *
练习15.17:尝试定义一个Disc_quote的对象,看看编译器给出的错误信息是什么。
IDE为Xcode,给出的错误信息是:Variable type 'Disc_quote' is an abstract class.
练习15.18:假设给定了第543页和第544页的类,同时已知每个对象的类型如注释所示,判断下面的哪些赋值语句是合法的。解释那些不合法的语句为什么不被允许:
Base *p=new B p=&d1;              //d1的类型是Pub_Derv p=&d2;              //d2的类型是Priv_Derv p=&d3;              //d3的类型是Prot_Derv p=&dd1;             //dd1的类型是Derived_from_Public p=&dd2;             //dd2的类型是Derived_from_Private p=&dd3;             //dd3的类型是Derived_from_Protected
答:只有d1和dd1才能够赋值。这是因为:
只有当派生类公有地继承基类时,用户代码才能使用派生类向基类的转换;也就是说,如果派生类继承基类的方式是受保护的或者私有的,则用户代码不能使用该转换。
在上题中,只有d1和dd1类是公有地继承基类,故只有他们才能完成向基类的转换。
练习15.19:假设第543页和544页的每个类都有如下形式的成员函数:
void memfcn(Base &b) { b=* }
对于每个类,分别判断上面的函数是否合法。
Derived_from_Private: private Priv_Derv这个类的函数不合法。
原因如下:
1.无论派生类以什么方式继承基类,派生类的成员函数和友元都能使用派生类向基类的转换;派生类向其直接基类的类型转换对于派生类的成员和函数来说永远是可访问的。
2.如果派生类继承基类的方式是公有地或者受保护的,则派生类的成员和友元可以使用派生类向基类的类型转换;反之,如果派生类继承基类的方式是私有的,则不能使用。
练习15.20:编写代码检验你对前面两题的回答是否正确。
#include &iostream& class Base { public:
void pub_mem(); protected:
int prot_ private:
char priv_ };
struct Pub_Derv:public Base {
int f(){return prot_}
void memfcn(Base &b)
cout&&&Pub_Derv&&&
struct Priv_Derv:private Base {
int f1() const {return prot_}
void memfcn(Base &b)
cout&&&Priv_Derv&&&
} }; struct Prot_Derv:protected Base {
int f2(){return prot_}
void memfcn(Base &b)
cout&&&Prot_Derv&&&
} }; struct Derived_from_Public:public Pub_Derv {
int use_base(){return prot_}
void memfcn(Base &b)
cout&&&Derived_from_Public&&&
struct Derived_from_Protected:protected Prot_Derv {
int use_base()
return prot_
void memfcn(Base &b)
cout&&&Derived_from_Protected&&&
} }; /*struct Derived_from_Private: private Priv_Derv {
int use_base()
void memfcn(Base &b)
} };*/ int main(int argc, const char * argv[]) {
Pub_Derv d1;
Priv_Derv d2;
Prot_Derv d3;
Derived_from_Public dd1;
// Derived_from_Private dd2;
Derived_from_Protected dd3;
Base *p=new B
//d1的类型是Pub_Derv
//d2的类型是Priv_Derv
//d3的类型是Prot_Derv
//dd1的类型是Derived_from_Public
//dd2的类型是Derived_from_Private
//dd3的类型是Derived_from_Protected
d1.memfcn(base);
d2.memfcn(base);
d3.memfcn(base);
dd1.memfcn(base);
//dd2.memfcn(base);
dd3.memfcn(base);
return 0; }
代码运行结果:
Pub_Derv Priv_Derv Prot_Derv Derived_from_Public Derived_from_Protected
练习15.21:从下面这些一般性抽象概念中任选一个(或者选一个你自己的),将其对应的一组类型组织成一个继承体系:
(a) 图像文件格式(如 gif, tiff, jpeg, bmp )
(b) 几何图元(如矩形,圆,球形,锥形)
(c) C++语言的类型(如类,函数,成员函数)
对(b)中的几何图元组织成一个继承层次,
基类Figure,
矩形Rectangle, 圆cicle, 球形sphere,锥形 Cone继承自Figure类。
练习15.22:对于你在上一题中选择的类,为其添加合适的虚函数及公有成员和受保护成员。
比如计算图形面积的函数 virtual double area();&
计算体积的函数virtual double cubage();&
求周长的函数 virtualdouble perimeter();
Figuer类的public成员可能有两个图元的尺寸:xSize, ySize,其他类的protected成员可能有cone类和球形的zSize即Z轴尺寸
练习15.23:假设第550页的D1类需要覆盖它继承而来的fcn函数,你应该如何对其进行修改?如果你修改之后fcn匹配了Base中的定义,则该节的那些调用语句将如何解析?
1.将D1类的fcn函数更改为 int fcn();
2.p2-&fcn(42) &这一条调用语句将会出错。
测试代码如下:
#include &iostream& class Base { public:
virtual int fcn()
cout&&&int fcn from Base&&&
class D1:public Base { public:
cout&&&int fcn from D1&&&
virtual void f2()
cout&&&void f2() from D1&&&
} }; class D2:public D1 { public:
int fcn(int )
cout&&&int fcn(int ) from D2&&&
cout&&&int fcn from D2&&&
cout&&&f2 from D2&&&
} }; int main(int argc, const char * argv[]) {
BD1 d1D2 d2
Base *bp1=&bobj,*bp2=&d1obj,*bp3=&d2
bp1-&fcn();
bp2-&fcn();
bp3-&fcn();
D1 *d1p=&d1obj,*d2p=&d2
bp2-&f2();
//错误,base类里面没有f2()的成员函数
d1p-&f2();
d2p-&f2();
Base *p1=&d2
p1-&fcn(42);
//错误,Base类中没有接受int实参的fcn
p2-&fcn(42);
//错误,D1类中没有接受int实参的fcn
p3-&fcn(43);
std::cout && &Hello, World!n&;
return 0; }
将错误代码注释后运行得到结果如下:
int fcn from Base int fcn from D1 int fcn from D2
void f2() from D1 f2 from D2
int fcn(int ) from D2
练习15.24:哪种类需要虚析构函数?虚析构函数必须执行什么样的操作?
作为基类使用的类应该具有虚析构函数,以保证在删除指向动态分配对象的基类指针时,根据指针实际指向的对象所属的类型运行适当的析构函数。
虚析构函数可以为空,即不执行任何操作,而当类中有指针类成员时,则需要自己定义虚析构函数,以对指针成员进行适当的清除。
练习15.25:我们为什么为Disc_quote定义一个默认构造函数?如果去除掉该构造函数的话会对Bulk_quote的行为会产生什么影响?
因为Disc_quote的默认构造函数会运行Quote的默认构造函数,而Quote默认构造函数会完成成员的初始化工作。
如果去除掉该构造函数的话,Bulk_quote的默认构造函数而无法完成Disc_quote的初始化工作。
练习15.26:定义Quote和Bulk_quote的拷贝控制成员,令其与合成的版本行为一致。为这些成员以及其他构造函数添加打印状态的语句,使得我们能够知道正在运行哪个程序。使用这些类编写程序,预测程序将创建和销毁哪些对象。重复实验,不断比较你的预测和实际输出结果是否相同,直到预测完全准确再结束。
#include &iostream& #include &string& #include &ostream&
class Quote { public:
Quote(const std::string &book=&&,double sales_price=0.0):
bookNo(book),price(sales_price)
cout&&&Quote constructor is running&&&
std::string isbn() const
return bookNo;
virtual double net_price(std::size_t n)const
//返回给定数量的书籍的销售总额,派生类改写并使用不同的折扣计算方法
virtual void debug()
cout&&&bookNo=&&&bookNo&&& price=&&&price&&
virtual ~Quote()
cout&&&Quote destructor is running&&&
friend ostream &operator &&(ostream&,Quote&);
std::string bookNo;
//书籍的ISBN编号 protected:
double price=0.0;
//代表普通状态下不打折的价格
ostream & operator &&(ostream&os,Quote &e) {
os&&&tUsing operator &&(ostream &,Quote &);&&& };
class Bulk_quote:public Quote { public:
Bulk_quote(const string &book=&&,double sales_price=0.0,size_t qty=0,double disc=0.0):
Quote(book,sales_price),min_qty(qty),discount(disc)
cout&&&Bulk_constructor is running&&&
double net_price(size_t cnt)const
if ( cnt & min_qty )
return cnt * ( 1- discount ) *
return cnt *
~Bulk_quote()
cout&&&Bulk_quote destructor is running&&&
size_t min_ };
ostream &operator&&(ostream &os,Bulk_quote& bq) {
os&&&tUsing operator &&(ostream&,Bulk_quote &)&&& }
int main(int argc, const char * argv[]) {
Quote base(&C++ Primer&,128.0);
Bulk_quote bulk(&Core Python Programming&,89,5,0.19);
cout&&base&&
cout&&bulk&&
return 0; }
运行结果如下:
Quote constructor is running Quote constructor is running Bulk_constructor is running
Using operator &&(ostream &,Quote &);
Using operator &&(ostream&,Bulk_quote &)
Bulk_quote destructor is running Quote destructor is running Quote destructor is running
练习15.27:重新定义你的Bulk_quote类,令其继承构造函数。
class Disc_quote:public Quote { public:
Disc_quote(const string &book=&&,double sales_price=0.0,size_t qty=0,double disc=0.0):Quote(book,sales_price),quantity(qty),discount(disc){}
double net_price(size_t cnt) const=0; protected:
class Bulk_quote : public Disc_quote {
using Disc_quote::Disc_
double net_price( size_t cnt ) const
if ( cnt & quantity )
return cnt * ( 1- discount ) *
return cnt *
感谢关注 Ithao123C/c++频道,是专门为互联网人打造的学习交流平台,全面满足互联网人工作与学习需求,更多互联网资讯尽在 IThao123!
Laravel是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。
Hadoop是一个由Apache基金会所开发的分布式系统基础架构。
用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。
Hadoop实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS。HDFS有高容错性的特点,并且设计用来部署在低廉的(low-cost)硬件上;而且它提供高吞吐量(high throughput)来访问应用程序的数据,适合那些有着超大数据集(large data set)的应用程序。HDFS放宽了(relax)POSIX的要求,可以以流的形式访问(streaming access)文件系统中的数据。
Hadoop的框架最核心的设计就是:HDFS和MapReduce。HDFS为海量的数据提供了存储,则MapReduce为海量的数据提供了计算。
产品设计是互联网产品经理的核心能力,一个好的产品经理一定在产品设计方面有扎实的功底,本专题将从互联网产品设计的几个方面谈谈产品设计
随着国内互联网的发展,产品经理岗位需求大幅增加,在国内,从事产品工作的大部分岗位为产品经理,其实现实中,很多从事产品工作的岗位是不能称为产品经理,主要原因是对产品经理的职责不明确,那产品经理的职责有哪些,本专题将详细介绍产品经理的主要职责
IThao123周刊The page is temporarily unavailable
nginx error!
The page you are looking for is temporarily unavailable.
Please try again later.
Website Administrator
Something has triggered an error on your
This is the default error page for
nginx that is distributed with
It is located
/usr/share/nginx/html/50x.html
You should customize this error page for your own
site or edit the error_page directive in
the nginx configuration file
/etc/nginx/nginx.conf.The page is temporarily unavailable
nginx error!
The page you are looking for is temporarily unavailable.
Please try again later.
Website Administrator
Something has triggered an error on your
This is the default error page for
nginx that is distributed with
It is located
/usr/share/nginx/html/50x.html
You should customize this error page for your own
site or edit the error_page directive in
the nginx configuration file
/etc/nginx/nginx.conf.The page is temporarily unavailable
nginx error!
The page you are looking for is temporarily unavailable.
Please try again later.
Website Administrator
Something has triggered an error on your
This is the default error page for
nginx that is distributed with
It is located
/usr/share/nginx/html/50x.html
You should customize this error page for your own
site or edit the error_page directive in
the nginx configuration file
/etc/nginx/nginx.conf.

我要回帖

更多关于 c primer plus 第6版 的文章

 

随机推荐