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 函数。