文档库 最新最全的文档下载
当前位置:文档库 › C++思考题题解

C++思考题题解

第二章思考题题解

(一)判断下列各种描述是否正确,对者划√,错者划

述是否正确,对者划√,错者划

否正确,对者划√,错者划

,错者划

者划

以下五小题均对!

(1) 引用的运行机理和指针完全相同,而其使用却方便的多。

(2) 引用的功能和指针相同,但却多一项,即从函数返回的引用可用作等式左值。例如:

//refer_4.cpp

//reference used as a return value of a function

#include

int Index;//自动初始化为0

int& getIndex(); //此为函数原型

void main()

{

int n;

n=getIndex(); //used as a right value, i.e. n=Index

//一般函数返回值只能用作右值

cout<

//只有以下引用返回值才能用作左值

getIndex( )=5; //used as a left value, i.e. Index=5

cout<

getIndex()++; //equivalent to Index++; i.e. Index=6

cout<

}

int& getIndex()

{

return Index; //getIndex() is used as a reference of Index

}

/* Results:

5

6 */

(3) 引用是“别名其表,指针其实”。也即,引用在使用时是一个别名,但实质上是一个指针。

(4) 虽然用户程序无法读取引用的地址,但引用本身具有一定地址。

可看§2.8.1“概念和定义”中:

[例2]另一个将引用重新赋值的例子

// refer_8.cpp

#include

void main()

{

int val1(10);

int &refv = val1;

val1 = 15;

cout<<"变量与引用的值:"<

cout<<"变量与引用的地址:"<<&val1<<","<<&refv<

int val2(20);

refv = val2; //即重新赋值val1 = val2;

cout<<"重新赋值后变量与引用的值:"<

}

/* Results:

变量与引用的值:15,15(程序中val1和refv同时由10变为15,实际上引用refv 包含了变量val1的地址)

变量与引用的地址:0x0012FF7C,0x0012FF7C(程序中变量和引用的地址相同。实际上并不相同。见程序refer_9.cpp和本程序的图解)

重新赋值后变量与引用的值:20,20(程序中两个变量值一起改变)*/

栈区

第一句

int val1(10);

第二句

int &refv = val1;

第三句val1 = 15; 第六句

int val2

(20); 第七句

refv = val2;

以上情况从何得知?只能根据该程序的汇编语言代码的分析才知道,还可见本章第四思考题,第二章也有程序ref_content_5.cpp能证明。

(5) 静态数据的定义语句(例如static int s = 5;),只在程序的编译过程中用于在

数据区内开辟空间,供存放静态数据之用;而并不参与程序运行。

(二)填空:

(1)被定义于所有函数之外的变量称为(全局)变量,也称(外部)变量。

(2)被定义于某个函数(程序块)之内的变量称为(局部)变量,也称(临时)

变量。

(3)静态变量分为(外部)静态变量和(内部)静态变量两种。这和前面两题相

对应。

(4) 所有函数的代码通常都被存放在内存的(代码)区。

全局变量和所有静态变量通常都被存放在内存的(数据)区。

所有函数中的局部变量、函数参数、所用通用寄存器的值、返主地址等通常在该函数被调用时,被存放在内存的(栈)区。

使用new所分配的空间被存放在内存的(堆)区。

(三)给出以下程序的运行结果:

(1) //cal_val2.cpp

//call by value

#include

void inc(int v)

{

v++;

}

void main()

{

int i=10;

inc(i);

cout<

}

/* Result:

10 */

(2) //cal_ptr2.cpp

//call by pointer

#include

void inc(int *v)

{

(*v)++;

}

void main()

{

int i=10;

inc(&i);

cout<

}

/* Result: 11 */

(3) //cal_ref2.cpp

//call by reference

#include

void inc(int &v)

{

++v;

}

void main()

{

int i=10;

inc(i);

cout<

}

/* Result:

11*/

(四)给出以下程序的运行结果,并画出程序中执行第一、第二、第三和第六语句后变量及其引用的栈区内存存储内容:

#include

void main()

{

int val; //(1)

int &refv = val; //(2)

val = 15; //(3)

cout<<"变量与引用的值:"<

cout<<"变量与引用的地址:"<<&val<<","<<&refv<

refv = 30; //(6)

cout<<"重新赋值后变量与引用的值:"<

}

/* Results:

变量与引用的值:15,15

变量与引用的地址:0x0012FF7C,0x0012FF7C

重新赋值后变量与引用的值:30,30

*/

栈区存储内容

第一句

int val;

第二句

int &refv = val;

第三句 val = 15;

第六句

refv = 30;

(五)给出以下程序的运行结果,并画出程序中执行第一、第二和第四语句后变量及其引用的内存存储内容:

// defining reference for heap area datum

#include void main() {

int *p = new int(10); int & ref = *p; cout<

cout<<*p<

/* Results: 10 50 */

栈区存储内容堆区存储内容第一句int *p = new int(10);

第二句int & ref = *p;

第四句ref = 50;

(六)给出以下程序的运行结果:

// exer_ch2_6.cpp

#include

static int s(3);

void fun(void);

void main()

{

cout <<"external static s(global)="<

fun( );

fun( );

}

void fun( )

{

static int b(3);

b += s;

cout<<"internal static b in fun="<

}

/* Results:

external static s(global)=3

internal static b in fun=6

internal static b in fun=9 */

请注意:语句“static int b(3);”只在编译阶段中使用,在程序运行时并不执行。(七)试问以下各变量位于何区?

// exer_ch2_7.cpp

// try to read the addresses of data, functions and heap

#include

int data = 23; // global datum

void main()

{

int i = 15; // local datum

int *ptr = new int(8); // datum in heap

cout<<"code address:"<

cout<<"global datum address:"<<&data<

cout<<"local datum address:"<<&i<

cout<<"pointer address:"<<&ptr<

cout<<"heap address:"<

cout<<"datum in heap:"<<*ptr<

delete ptr;

}

/* Results:

code address:0x00401014

global datum address:0x00428D64

local datum address:0x0012FF7C

pointer address:0x0012FF78

heap address:0x00431AE0

datum in heap:8

*/

data位于数据区、i位于栈区、ptr位于栈区、*ptr位于堆区、main( )位于代码区。

第三章思考题题解

(一)选择填空:

答案:(1) C (2) B (3) D (4) A (5) C (6) A (7) D (8) B (9) D。

(1) 关于类定义格式的描述中,( C )是错的。

( C )是错的。

A. 一般类的定义格式可分为类的声明(也称类的接口)部分和成员函数定义

(也称类的实现)部分共两部分,有时这两部分也可合并为一个统一的类的定义。

格式可分为类的声明(也称类的接口)部分和成员函数定义(也称类的实现)部分共两部分,有时这两部分也可合并为一个统一的类的定义。

举例如下:

(1)统一的类的定义:

class integ

{

int j; //私有属性数据

public:

integ( ) { j = 6; } //构造函数定义

int sq() { return j*j; } //成员函数定义

};

(2)(A)类的声明(也称类的接口)部分:

class integ

{

int j; //私有属性数据

public:

integ( ); //构造函数原型

int sq( ); //成员函数原型

};

只包括成员函数的函数原型,也可能包括构造函数和析构函数的函数定义。

但不包括成员函数的定义部分(即函数体)。

(B)函数定义部分(很可能在另一个文件内)

integ::integ ( ) { j = 6; } //构造函数体

integ::int sq( ) { return j*j; } //成员函数体

B. 类中一般包含有数据成员和成员函数。

. 类中一般包含有数据成员和成员函数。

C. 类对象的内存存储内容中,所有数据(包括静态数据成员和非静态数据成

员)都存于内存数据区内。不对!只有静态数据成员存于数据区内,而

非静态数据成员则存于栈区内。

D. 类对象的成员函数的代码部分都存于内存代码区内。

(2) 关于类成员的描述中,( B)是错的。

的描述中,( B)是错的。

A.类中可以说明或定义一个或多个成员函数。

B.类中的成员函数的定义只能放在类体外。

错!成员函数的定义一般放在类体外,但也可放在类体内。

C. 在类体外使用数据成员时,须使用类名及作用域运算符(::)来指明

(限定)该数据成员(例如base::a)。

(3) 在类的静态成员的描述中,(D )是错的。

在类的静态成员的描述中,(D )是错的。

A.静态成员分为静态数据成员和静态成员函数。

B. 静态数据成员声明后必须在类体外进行说明或定义,以便初始化。例如:

class counter

{

static int count; //用于表示已建立的对象数

…………

public:

counter ( ) {……}//不负责静态数据的初始化

…………

};

int counter::count; // this should not be omitted

C. 静态数据成员初始化不使用其构造函数。(因为必须在类体外初始化)

D. 静态成员函数可以不使用类名和作用域运算符而直接访问该类的某个具

体对象的非静态成员。

(错!因静态成员函数没有this指针)。

由于静态成员函数中没有this指针,无法判断当前是哪一个对象。也就无法找到某一对象的数据成员。因此,静态成员函数要识别对象,只能依靠参数传递对象名来识别对象。

例如第三章§3.6.2.2[例3],以及[例4]的static int set_total_length (string obj)

{……}

(4) 在友元的描述中,( A)是错的:

A. 一个类的友元函数是该类的成员函数。(错!它不是成员函数,

而是独立于类以外的函数,但被授权能直接访问类中的私有成员,所以在类体外调用友元函数时,不必也不能使用类名及作用域运算符(::)来对它加以指明或限定)。

B. 友元函数可直接访问类中的私有成员。

C.友元函数损害封装性,应限用。

D.友元类中的所有成员函数都是友元函数。

(5) 在有关类和对象的描述中,( D )是错的:

A. 对象是类的一个实例。

B. 任何一个对象只能属于一个类。

C. 类和对象的关系与数据类型和变量的关系相似。(例如:int j;

与base obj;)

D. 一个类只能有一个对象。(错!对象数量并无限制。正如整型

变量的数量毫无限制一样。)。

(6) 下列关于对象数组的描述中,(A)是错误的。

A. 对象数组只能赋初值而不能再赋值。(错!可以无数次赋值,和普通数组相同。事实上,有些情况下,建立数组时无法初始化,必须再次赋值。)

B. 对象数组的下标(序号)从0开始。

C. 对象数组的每个元素都是相同类的对象。

D. 对象数组的数组名是一个常量指针。

(7) 下列关于子对象的描述中,( D )是错误的。

A. 子对象是另一个类(复合类)的一个数据成员。

B. 子对象不可以是本复合类的对象而应是其它类的对象。

C. 对子对象的初始化必须通过构造函数中的初始化列表。

D. 一个类中只能含有一个子对象作其成员。(错!数量不限)。

(8) 在new运算符的下列描述中,(B )是错误的。

A. 它可以为创建对象或对象数组而动态地在堆区内分配空间。

B. 用它创建对象数组时必须指定初始值。(错!事实上无法指定,最多只能使用

缺省值)。如果必须在创建对象数组时指定初始值,则可不使用new在堆区内分配空间,而使用普通方式,在栈区内创建对象数组。如下:

class base {……

public: base(int k, int j) {……} };

void main( ) { base arr[3]={ base(5,6), base(7,8), base(9,10) };这类似于int arr[3] = { 7, 8, 9 }; )

C. 当构造函数使用它在堆区内创建对象或对象数组时,在程序结束前应使用运算符delete来释放所分配的堆区空间。

(9) 在delete运算符的下列描述中,( D )是错误的。

A. 用它可以释放先前用new运算符创建的为对象或对象数组分配的堆区空间。

B. 用它释放一个对象时,它作用于一个new所返回的指针。

C. 用它释放一个对象数组时,它作用的指针名前须加下标运算符[ ]。

D. 用它释放一个对象的堆区空间时,它同时删除new运算符所使用的指针。(错!事实上指针没有删除,仍然保留,可再次使用)。

(二)判断下列各种描述是否正确,对者划√,错者划

述是否正确,对者划√,错者划

否正确,对者划√,错者划

,错者划

者划

答案:(1)√(2)√(3)

(1) 建立一个类的对象时,系统将其非静态数据成员存储于该对象的栈区内。而该类的静态数据成员和成员函数代码则分别存储于数据区和代码区内。√

(2) 如果一个成员函数只访问一个类的静态数据成员,则将该成员函数定义为静态成员函数将更方便。√(此做法的优点是可在建立对象之前就调用静态函数来访问静态数据,参阅第三章§3.6.2.2[例1]程序static_fun_3.cpp。其中主函数为:void main()

{

counter::show( );

//如不将函数counter::show( )定义为静态函数,则将如下出错:// error C2352: 'counter::show' :

// illegal call of non-static member function

counter *ptr1 = new counter;

……

}

(3) 可在类的构造函数的初始化列表中对该类的静态数据成员进行初始化。 (静态数据成员只能在类体之内声明,并在类体之外初始化。例如int [static] s;自动初始化为零,

或int [static] s(3); 初始化为一定值)

(三)给出以下程序的运行结果:

// exer_3_3.cpp

#include

class C {

static int c;

public:

C( ) { cout<<+ +c<

static int Getc( )

{ return c; }

~C( ) { cout<

};

int C::c; //自动初始化为零

void main( )

{

C c1, c2, c3;

cout<

}

/* Results:

1

2

3

3 // C::Getc( )所显示内容

3

2

1 */

(四)给出以下程序的运行结果:

// exer_ch3_4.cpp

#include

class M

{

int m1, m2;

public:

M(int i, int j) { m1=i; m2=j; }

void Sum(M a, M b) {

m1=a.m1+b.m1;

m2=a.m2+b.m2;

}

void print( )

{ cout<<"m1="<

};

void main()

{

M a(30, 70);

M b(a); // 或M b = a;

b.Sum(a, b);// 类似于b=a+b

b.print( );

}

/* Results:

m1=60,m2=140

*/

(五)给出以下程序的运行结果:

// exer_ch3_5.cpp

#include

class AA {

public:

int a;

AA (int x) { a = x; cout<<"Cons-"<

~AA ( ) { cout<<"Des-"<

};

void inc_by_value(AA obj) //形参是class AA的对象obj {

obj.a++;

}

void inc_by_refer(AA & obj) //形参是class AA的对象obj的引用,实即指针

{

obj.a++;

}

void main()

{

AA obj(50);

inc_by_value(obj);

cout<<"inc_by_value:a="<

inc_by_refer(obj);

cout<<"inc_by_reference:a="<

}

/* Results:

Cons-50(建立obj时)

Des-51(退出函数inc_by_value时删除临时对象)

inc_by_value:a=50

inc_by_reference:a=51

Des-51(退出主函数时)

*/

(六)给出以下程序的运行结果:

// exer_ch3_6.cpp

#include

class figure

{

double d;

public:

figure ( double m )

{ d = m; cout<<"CONS-sub:"<

};

class point

{

int x;

figure sub_obj; // sub_obj为子对象

public:

point (int a, double d) : x(a), sub_obj(d) //将子对象初始化

{ cout<<"CONS:"<

~point( ) { cout<<"Des:"<

};

void main()

{

point objp1(123, 98.76);

}

/* Results:

CONS-sub:98.76(建立objp1时)

CONS:123

Des:123(退出主函数时删除objp1)

Des-sub:98.76

*/

(七)判断下列描述是否正确,对者划√,错者划 。

答案:(1)√ (2)√(3)√ (4)√(5)

(1) 对象和指向对象的指针都可以用作函数参数。√

(2) 对象数组的元素必须是同一个类的对象。√

(3) 一维对象指针数组的每个元素应该是同一个类的不同对象的地

址值。√

(4) 运算符new可以在堆区内创建变量或对象,也可以创建变量数组

或对象数组。√

(5) 子对象的初始化可在复合类的构造函数的函数体内进行。 (应在构造函数的初始化列表中而不是在函数体内进行,见第六题)(八)给出以下程序的运行结果,并画出对象obj的栈区存储内容。#include

class B

{

int b1, b2;

public:

B(int i, int j);

void printB( );

}; //这是典型的类的接口(声明)

B::B(int i, int j)

{

b1 = i;

b2 = j;

}

void B::printB( )

{

cout<<"b1="<

}

class A

{

int a;

B sub_obj;

public:

A(int i, int j, int k);

void printA( );

};

A::A(int i, int j, int k) : sub_obj(i, j), a(k) { }

void A::printA( )

{

sub_obj.printB( );

cout<<"a="<

void main()

{

A obj(12, 65, 100);

obj.printA( );

}

/* Results:

b1=12,b2=65

a=100 */

class A的对象obj的栈区存储内容

请注意:栈区存储内容中各单元的排列顺序与构造函数的调用顺序并不一

定相同。此排列顺序决定于类定义中各变量的声明顺序。

如类定义改为:

class A

{

B obj;

int a;

……

}

则栈区存储内容将为:

但构造函数的调用顺序并无变化。

(九)给出以下程序的运行结果,并画出主程序第一句和第二句后对象obj的双区存储内容。

#include

class M

{

int x;

static int s;

public:

M (int a) { x=a;}

void add (int b ) { s+=b;}

void show ( ) { cout<<"object datum : "<

static void show_s( ) { cout<<"static datum : "<

int M::s=3; void main() {

M obj(6); obj.add(7); obj.show(); M::show_s( ); }

/* Results:

object datum : 6 static datum : 10 */

栈区 数据区 主程序第一句“M obj(6)”后

主程序第二句“obj.add(7)”后

(十)给出以下程序的运行结果:

// To show different status of auto, static and external data // static and external data are initialized only once // and exist all the time #include void static_f ( void ); void auto_f ( void ); void external_f( void ); int g = 9; void main() {

auto_f (); auto_f ();

static_f (); static_f ();

external_f (); external_f (); }

// function to read and increment an auto datum void auto_f ( void )

{

int i = 3;

i += 3;

cout << i << endl;

}

// function to read and increment a static datum

void static_f ( void )

{

static i = 6; //i.e. static int i = 6;此句不参加运行

i += 3;

cout << i << endl;

}

// function to read and increment an external datum

void external_f( void )

{

g += 3;

cout << g << endl;

}

/* Results:

6

6

9

12

12

15*/

(十一)填空:

(1)一般程序有四个内存分区,它们是:(代码区)、(数据区)、(栈区)和(堆区)。

(2)(代码区)用于存放主函数和各子函数(包括各类中的成员函数)代码。(3)(数据区)用于存放全局变量、静态变量和常量数据。

(4)(栈区)用于存放局部变量,函数参数,寄存器值等。

(5)(堆区)用于为由new所创建的对象动态地分配存储空间。

第四章思考题题解

(一)选择填空:

答案:(1) C (2) A (3) B (4) C

(1) 下列对派生类的描述中,(C)是错误的。

A. 一个派生类可以用作另一个派生类的基类。

B. 派生类至少应有一个基类。

C. 基类中成员被派生类继承后其映射的访问权限并无变化。(错!事实上映射的访问权限决定于基类中的访问权限和派生方式也即继承方式两者,因此映射的访问权限随着派生方式不同而不同)。

D. 派生类对象的栈区内存存储内容中除了本派生类部分的所有

非静态数据成员外,还首先包含了它的所有基类部分的所有非静态数

据成员。

(2) 主函数main可以访问派生类对象中哪一类映射的基类成员?(A)

A. 公有继承的基类部分的公有成员。

B. 公有继承的基类部分的保护成员(只准派生类的成员函数访问)。

C. 公有继承的基类部分的私有成员(任何派生类的成员函数都不准访问)。

D. 保护继承的基类部分的公有成员(与B相同,只准派生类的成员函数访问)。

(3) 多继承派生类建立对象时,( B )被最先调用。

A. 派生类自己的构造函数。

B. 祖先虚基类的构造函数。

C. 祖先非虚基类的构造函数。

D. 派生类中子对象的构造函数。

九字方针:“先祖先(基类),再客人(子对象),后自己(派生类本身)”。

辅助规则:同一层中虚基类优先。

构造函数调用顺序为B, C, D, A

(4) 下列关键字中,( C )不是类定义中使用的关键字。

关键字中,( C )不是类定义中使用的关键字。

的关键字。

A. class

B. public

C. switch(开关语句用于实现多项选择结构)

. public C. switch(开关语句用于实现多项选择结构)

tch(开关语句用于实现多项选择结构)

D. private

(二)判断下列描述的正确性,对者划√,错者划

,错者划

者划

答案:(1)√ (2) (3) (4) (5) (6)√(7)

(1) C++语言中,允许单继承,也允许多继承。√

(2) 派生类不能再派生出新的派生类。

(3) 在公有继承中,派生类对象的成员函数可以访问基类部分中的私有成员。 (只

能访问映射的基类部分中的公有和保护成员,因公有继承中基类的私有属性映射为“不可访问” )

(4) 在公有继承中,派生类对象的成员函数不可以访问映射的基类部分中的保护

成员。 (可以访问,因公有继承中基类的保护属性仍然映射为保护属性)

(5)在私有继承中,派生类对象的成员函数不可以访问基类部分中的公有成员。

(可以访问,因私有继承中基类的公有属性仍然映射为私有属性)

(6)在保护继承中,派生类对象的成员函数可以访问基类部分中的保护成员。√(可以访问,因保护继承中基类的保护属性仍然映射为保护属性)

(可以访问,因保护继承中基类的保护属性仍然映射为保护属性)

(7)用class定义的类中,缺省的访问权限是公有的。 (缺省的访问权限应是私有的)。

s定义的类中,缺省的访问权限是公有的。 (缺省的访问权限应是私有的)。

义的类中,缺省的访问权限是公有的。 (缺省的访问权限应是私有的)。

(三)写出以下程序运行结果,画出以下题中的DAG和访问控制表// exer_ch4_3.cpp

#include

class A

{

int a,b;

public:

A(int i, int j)

{a=i; b=j;}

void Move(int x, int y)

{a+=x; b+=y;}

void Show( )

{cout<<'('<

};

class B : public A

{

int x, y;

public:

B(int i, int j, int k, int l) : A(i, j)

{x=k; y=l;}

};

void main( )

{

B b(3, 4, 5, 6);

b.Move(7, 8);

b.Show( );

}

/* Results:

(10, 12) */

DAG

栈区存储内容

访问控制表

(四)画出以下程序的访问控制表,并根据该表找出程序中错误语句,将它删去后显示运行结果。

//acc_mod_6_1.cpp

#include

class A

{

protected:

void f( int a ) { cout<< a << endl; }

void g( ) { cout<< "g( )" << endl; }

};

class B: A //private derived

{

public:

void h( ) { cout<< "h( )" << endl; }

相关文档
相关文档 最新文档