C++ primer 习题笔记第13~15章

1、下面第二个初始化不能编译。可以从 vector 的定义得出什么推断?
vector<int> v1(42);

vector<int> v2 = 42;

【解答】

若能编译成功说明,这是个复制初始化,创建 v2 时,首先调用接受一个 int 型形参的 vector 构造函数,创建一个临时 vector 对象,然后再调用复制构造函数用这个临时对象来初始化 v2。现在不能编译,说明vector 没有定义复制构造函数。


2、假定 Point 为类类型,该类类型有一个复制构造函数,指出下面程序段中每一个使用了复制构造函数的地方:

Point global;
Point foo_bar( Point arg ) //  调用此函数时,将实参对象的副本传递给形参 Point 的对象 arg
{
      Pint local = arg;   //  调用复制构造函数,将局部对象 local 初始化为形参 arg 的副本。
      Point  *heap  =  new  Point(  global  );   //  调用复制构造函数用全局对象 global 来初始化Point 对象*heap
      *heap = local;
       Point pa[4] = { local, *heap  };   //  使用数组初始化列表来初始化数组的每个元素。
      retur n  *heap;    //  从函数返回 Point 对象*heap 的副本
}


3、哪个类定义可能需要一个复制构造函数?
(a)  包含四个 float 成员的 Point3w 类。
(b) Matrix 类,其中,实际矩阵在构造函数中动态分配,在析构函数中删除。
(c)  Payroll 类,在这个类中为每个对象提供唯一 ID 。
(d)  Word 类,包含一个 string 和一个以行列位置对为元素的 vector。 

【解答】
(b)需要,涉及到指针及动态分配
(c)需要,在根据已存在的 Payroll 对象创建其副本时,需要提供唯一的 ID.
其他的均可以调用编译器的提供的复制构造函数,或者调用类类型的 string 和 vector 的复制构造函数。


4、复制构造函数的形参并不限制为 const,但必须是一个引用,解释这个限制的基本原理,例如,解释为什么下面的定义不能工作,
Sales_item::Sales_item(  const Sales_item rhs );

【解答】
它不能工作的原因是:当形参为非引用类型时,将复制实参的值,给这个 copy constructor,但是,每当以传值方式传递参数时,会导致调用复制构造函数,因此,如果要使用以传值方式传递参数的 copy constructor,必须使用一个“不以传值方式传递参数”的 copy  constructor, 否 则 就 会 导 致 copy constructor 的无穷递归调用。这个“不以传值方式传递参数”的方法就是使用  形参是一个引用  的copy constructor,即以传地址的方式传递参数。


5、类何时需要定义复制操作符?

【解答】
在需要定义复制构造函数时,也需要定义赋值操作符,即如果一个类(1)类中包含指针型数据成员,(2)或者在进行赋值操作时需要做一些特定工作,则该类需要定义赋值操作符。


6、定义一个 Employee 类,包含雇员名字和一个唯一的雇员标识,为该类定义默认构造函数和参数为表示雇员名字的 string 构造函数。如果该类需要复制构造函数或赋值操作符,实现这些函数。

【解答】
class Employee
{
public:
     Employee():  ID(cnt)  {   cnt++  ;  }    //  默认构造函数
     Employee(  const  std::string  &na  ):  name(  na  ), ID(cnt) 
     {   cnt++;    } //  构造函数
     //  拷贝构造函数
     Employee(  const  Employee  &  rhs  )  : name( rhs.name ) , ID(cnt)  
     { cnt++; }
     //  赋值操作符
     Employee & operator= ( const Employee & rhs ) 
     { 
          name = rhs.name;
          retur n *this;
     }
private:
      string name;
      int ID;
      static int cnt;
};
另外需要在类外对 static 成员进行初始化:
int Employee::cnt =1 ;


7、“cobble‖ ” == “store‖”  应用了 C++语言内置版本的重载==


8、使用标准库函数对象和函数适配器,定义一个对象用于:

(a)  查找大于 1024 的所有值。
(b)  查找不等于 pooh 的所有字符串。
(c)  将所有值乘以 2

【解答】
(a)  find_if(  vec.begin(),  vec.end(), bind2nd(  greater<int>(), 1024 ) );
(b)  find_i f  (  svec.begin(),  svec.end(), bind2nd(  not_equal_to<string>(),  ―pooh‖);
(c)  transform(  ivec.begin(),  ivec.end(),  ivec.begin(), bind2nd(  multiplies<int>(),  2 ) );


9、使用标准库函数对象代替 GT_cls 来查找指定长度的单词。

【解答】
输入一个指定长度:
vector<string> text;
// …   // input words into text
string::size_type len;
cin >> len;
string *w;
for  (  vector<string>::iterator  it  =  text.begin();  it  != text.end(); ++it )
{
      w  =  find_if  (  it,  text.end(), bind2nd(  equal_to<string::size_type>(), len) ); 
}

      cout  <<  "The  words  whose  length  is  "<<  len  <<  "was found.,It is:"<< *w <<endl;


10、解释这两个转换操作符之间的不同:
class Integral
{
public:
     operator const int();
     operator int() const;
};

【解答】
不同:前者将对象转换为 const  int 值,后者将对象转换为 int 值,前者太严格,限制使用在可以使用const int  值的地方,只保留后者,将变得更为通用。


11、哪个 calc() 函数是如下函数调用的最佳可行函数?列出调用每个函数所需的转换序列,并解释为什么所选定的就是最佳可行函数。
class LongDouble
{
public:
      LongDouble( double  );
      // …
};
void calc( int );
void calc( LongDouble );
double dval;
calc( dval ); // which function?

【解答】
最佳可行函数是 void  calc(int),   调用此函数的转换为:将实参 double 类型转换为 int 类型的,为标准转换;调用 void  calc(  LongDouble)函数时,将实参从 double 转换为 LongDouble 类型,为类类型转换,因为标准转换优于类类型转换,所以第一个函数为最佳可行函数。


12、对于下面的类,列出 C1 中的成员函数访问ConcreteBase 的 static 成员的所有方式,列出 C2 类型的对象访问这些成员的所有方式。
struct ConcreteBase
{
      static std::size_t object_count();
protected:
      static std::size_t obj_count;
}; 
struct C1 : public ConcreteBase { //…  }
struct C2 : public ConcreteBase { // …  }

【解答】
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()


13、说明在什么情况下类应该具有虚析构函数。

【解答】
作为基类使用的类应该具有虚析构函数,以保证在删除指向动态分配对象的基类指针时,根据指针实际指向的对象所属的类型运行适当的析构函数。


14、虚析构函数必须执行什么操作?

【解答】
虚析构函数可以为空,即不执行任何操作,而当类中有指针类成员时,则需要自己定义虚析构函数,以对指针成员进行适当的清除。


15、通过指向基类对象的指针访问其protected的成员是错误的,应该将指针定义为指向子类的对象的指针。


16、假定 Derived 继承 Base,并且 Base 将下面的函数定义为虚函数,假定 Derived 打算定义自己的这个虚函数的版本,确定在 Derived 中哪个声明是错误的,并指出为什么错。
(a) Base* Base::copy( Base* );
Base* Derived::copy( Derived* );
(b) Base* Base::copy( Base* 0;
Derived* Derived::copy( Base* );
(c)  Ostream& Base::print( int, ostream& = cout );
ostream& Derived::print( int, ostream& );
(d) void Base::eval() const;
void Derived::eval();

【解答】
(a)  错了,因为 Derived 中声明的 copy 是一个非虚函数,而不是对 Base 中的虚函数 copy 的重载,因为派生类的重定义的虚函数必须与基类中的虚函数具有相同原型。而且此时 Derived 中定义的 copy 函数还屏蔽了基类Base 的 copy 函数。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值