C++习题与解答

更新时间:2024-07-01 20:56:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

第6章 ;类和对象(一)

练习题6

6.1 判断题

× 1.使用class定义的类,其默认的访问权限是公有的,使用struct定义的类,其默认的访问权限是私有的。

× 2.类中的成员函数都是公有的,数据成员都是私有的。

× 3.定义在类体内的成员函数是内联函数,定义在类体外的成员函数不能是内联函数。 √ 4.类定义后,它的成员个数及名称就不会再被改变了。

× 5.定义或说明对象时,系统会自动调用构造函数为创建的对象初始化。如果类中没有定义任何构造函数时,就无法给定义的对象初始化。

√ 6.定义一个对象时,系统只为该对象的数据成员开辟内存空间,而成员函数是同类对象共享的。

√ 7.对象成员的表示方法与结构变量成员的表示方法相同。

√ 8.创建对象时系统自动调用相应的构造函数为对象初始化,没有相应的构造函数时,系统会自动生成。

√ 9.构造函数是一个其名与类名相同的特殊的成员函数。 × 10.析构函数是一个函数体为空的成员函数。

√ 11.构造函数和析构函数都是系统自动调用的成员函数。 × 12.构造函数和析构函数都可以重载。

√ 13.成员函数与一般函数一样可以重载、内联和设置参数的默认值。 × 14.静态成员是指静态对象的成员。

× 15.静态数据成员必须在构造函数的成员初始化列表中进行初始化。 √ 16.静态成员都可以使用类名加作用域运算符的方法来引用。

× 17.静态成员函数中引用静态数据成员和非静态数据成员的方式是相同的。 √ 18.常成员指的是类体内使用const关键字说明的常数据成员和常成员函数。

× 19.常数据成员在常成员函数中的值是不允许改变的,而在非常成员函数中是允许改变的。

√ 20.常对象需要引用常成员函数,而不能引用非常成员函数。 × 21.常对象的数据成员都是常数据成员。

√ 22.友元函数是说明在类体内的非成员函数,它可以访问类中的所有成员。

× 23.可以把一个一般函数说明为某类的友元函数,也可以将某类的成员函数说明为另类的友元函数。

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

√ 25.类型转换函数是一种特殊的成员函数,定义时不加类型说明,无函数参数。 √ 26.单参数的构造函数具有类型转换的作用。 6.2 单选题

1.下列关于类的定义格式的描述中,错误的是( C )。 A.类中成员有3种访问权限

B.类的定义可分说明部分和实现部分

C.类中成员函数都是公有的,数据成员都是私有的 D.定义类的关键字通常用class,也可用struct

2.下列关键字中,不属于定义类时使用的关键字是( D )。

1

A.class B.struct

C.public D.default

3.下列关于成员函数的描述中,错误的是( A )。 4.下列关于对象的描述中,错误的是(5.下列关于构造函数的描述中,错误的是(6.下列关于析构函数的描述中,错误的是(7.下列关于静态成员的描述中,错误的是(

8.下列关于常成员的描述中,错误的是(9.下列关于友元函数的描述中,错误的是(A.成员函数的定义必须在类体外

B.成员函数可以是公有的,也可以是私有的

C.成员函数在类体外定义时,前加inline可为内联函数 D.成员函数可以设置参数的默认值

D )。 A.定义对象时系统会自动进行初始化

B.对象成员的表示与C语言中结构变量的成员表示相同 C.属于同一个类的对象占有内存字节数相同 D.一个类所能创建对象的个数是有限制的

C )。 A.构造函数可以重载 B.构造函数名同类名

C.带参数的构造函数具有类型转换作用 D.构造函数是系统自动调用的

A )。 A.析构函数的函数体都为空 B.析构函数是用来释放对象的 C.析构函数是系统自动调用的 D.析构函数是不能重载的

C )。 A.静态成员都是使用static来说明的

B.静态成员是属于类的,不是属于某个对象的

C.静态成员只可以用类名加作用域运算符来引用,不可用对象

D.静态数据成员的初始化是在类体外进行的 C )。 A.常成员是用关键字const说明的

B.常成员有常数据成员和常成员函数两种

C.常数据成员的初始化是在类体内定义它时进行的 D.常数据成员的值是不可以改变的

B )。 A.友元函数不是成员函数

2

引用 B.友元函数只可访问类的私有成员 C.友元函数的调用方法同一般函数

D.友元函数可以是另一类中的成员函数

10.下列关于类型转换函数的描述中,错误的是( C )。

A.类型转换函数是一种成员函数

B.类型转换函数定义时不指出类型,也没有参数

C.类型转换函数的功能是将其函数名所指定的类型转换为该

类类型

D.类型转换函数在一个类中可定义多个

6.3 填空题

1.类体内成员有3个访问权限,说明它们的关键字分别是 公有 、 私有 和 保护 。 2.使用class定义的表中,成员的默认访问权限是 私有 的;由struct定义的类中,成员的默认的访问权限是 公有 的。

3.如果一个类中没有定义任何构造函数时,系统会自动提供一个 默认 构造函数;同样,类中没有定义析构函数时,系统会自动提供一个 默认 析构函数。

4.静态成员是属于 类 的,它除了可以通过对象名来引用外,还可以使用 类名限定 来引用。

5.友元函数是被说明在 类体 内的 非 成员函数。友元函数可访问该类中的 成员。

6.完成下列类的定义。

class A {

public:

A() { a=0; }

int int Geta( A &m); private: int a; };

int Geta( A &m) { return m.a; }

6.4 分析下列程序的输出结果 1.

#include class A {

public: A() {

a1=a2=0;

cout<<\ }

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

{ cout<<\ } void Print()

{ cout<<\ } private:

3

int a1,a2; };

A::A(int i,int j) { a1=i; a2=j;

cout<<\ }

void main() {

A a,b(5,8); a.Print(); b.Print(); }

答: Default constructor called. Constructor called. a1=0,a2=0 a1=5,a2=8 Destructor called. Destructor called.

2.

#include class B { public: B()

{ cout<<++b<

{ cout<

int B::b=10; void main() {

B b1,b2,b3;

cout<

4

13 13 12 11

3.

#include class Date {

public:

Date(int y,int m,int d) {

year=y; month=m; day=d; }

friend void Print(Date &); private:

int year,month,day; };

void Print(Date &d) {

cout<

void main() {

Date d1(2005,10,1),d2(2005,12,9); Print(d1); Print(d2); }

答: 2005/10/1 2005/12/9

4.

#include class C {

public:

C(int i,int j)

{ c1=i;c2=j; } void Sum(C a,C b) {

c1=a.c1+b.c1; c2=a.c2+b.c2; }

void Print()

{ cout<<\ } private: int c1,c2; };

void main() {

C a(6,9); C b(a); C c(b); c.Sum(a,b); c.Print(); }

答: c1=12,c2=18

5

5.

#include class S {

public: S()

{ PC=0; } S(S &s) {

PC=s.PC;

for(int i=0;i

void Empty() { PC=0; } int IsEmpty()

{ return PC==0; } int IsMemberOf(int n); int Add(int n); void Print(); private:

int elems[100],PC; };

int S::IsMemberOf(int n) {

for(int i=0;i

int S::Add(int n) {

if(IsMemberOf(n)) return 1; else if(PC==100) return 0; else {

elems[PC++]=n; return 1; } }

void S::Print() {

cout<<'{';

for(int i=0;i0)

cout<

void main() { S a;

cout<

6

a.Print(); S b;

for(int i=1;i<=5;i++) b.Add(i);

b.Print();

cout<

c.Print(); } 答: 1 {}

{1,2,3,4,5} 1 0

{1,2,3,4,5,6,7,8,9,10}

6.5 编程题

1.按下列要求编程:

(1)定义一个描述矩形的类Rectangle,包括的数据成员有宽(width)和长(length); (2)计算矩形周长; (3)计算矩形面积; (4)改变矩形大小。 通过实例验证其正确性。 答:编程如下:

#include class Rectangle {

public:

Rectangle(int a,int b) { width=a; length=b; } int Area()

{ return width*length; } int Periment() { return 2*(width+length); } void Changesize(int a,int b) { width=a; length=b; } void Print(); private:

int width,length; };

void Rectangle::Print() {

cout<<\ cout<<\ }

void main() {

7

Rectangle r(5,8); r.Print(); r.Changesize(3,9); r.Print(); }

2. 编程实现一个简单的计算器。要求从键盘上输入两个浮点数,计算出它们的加、减、

乘、除运算的结果。 答:编程如下:

#include class ASMD {

public:

ASMD(double a,double b) { x=a; y=b; } void Addition()

{ cout<

{ cout<

{ cout<

{ cout<

double x,y; };

void ASMD::Print() {

Addition(); Subtration(); Multiply(); Divison(); }

void main() {

ASMD a(40,8); a.Print(); }

3.编一个关于求多个某门功课总分和平均分的程序。具体要求如下:

(1)每个学生信息包括姓名和某门功课成绩。 (2)假设5个学生。

(3)使用静态成员计算5个学生的总成绩和平均分。

答:编程如下:

#include

8

#include class Student {

public:

Student(char s[],int gr)

{ strcpy(name,s); grade=gr; totalize+=gr; } static void Print(); private:

char name[10]; int grade;

static int totalize; };

int Student::totalize=0; void Student::Print() {

cout<<\总成绩为 \平均成绩为 \

}

void main() {

Student

s1(\

Student::Print(); }

6.6 简单回答下列问题 1. 一个类中是否必须有用户定义的构造函数?如果用户没有定义构造函数,又如何对

创建的对象初始化?

答:一个类用户可以不定义构造函数,这时系统自动提供一个默认的构造函数,并可用该构造函数对创建的对象初始化。 2. 拷贝构造函数具有几个参数?它有类型转换的作用吗?

答:拷贝构造函数具有一个参数,即为该类对象的引用。拷贝构造函数没有类型转换作用。 3. 静态成员属于类的,是否每个对象都可以引用该静态成员? 答:可以。 4. 常对象可以引用非常成员函数吗?非常对象可以引用常成员函数吗? 答:不可以。可以。

5.友元函数能否访问类中的保护成员?友元函数访问类中私有成员与成员函数访问私有成员的形式相同吗?

答:能。相同。

9

第7章 类和对象(二)

练习题7

7.1 判断题

× 1.定义对象指针时也要调用构造函数。

√ 2.对象指针可用同类对象的地址值给它赋值。 × 3.对象指针成员表示与对象引用相同。

√ 4.常类型指针有两种,一种是指针的地址值是常量,另一种是指针所指向的变量或对象是常量。

× 5.指向对象的常指针的地址值是可以改变的。 × 6.指向常对象的指针所指向的对象是可以改变的。

√ 7.this指针是系统生成的指向当前被某个成员函数操作对象的指针。 × 8.对象引用可以用一个同类对象的地址值对它赋值。

× 9.定义对象引用时,可以对其引用进行初始化,也可以不进行初始化。 × 10.对象数组的元素可以是不同类的对象。

× 11.对象指针数组可以使用不同类的对象的地址值进行初始化。 × 12.给对象数组元素赋值时都要创建临时对象。 √ 13.指向一维对象数组的指针是一个二级指针。 × 14.自身类对象可作该类的子对象。

√ 15.子对象的初始化要在构造函数的成员初始化列表中进行。 √ 16.使用new运算符创建的对象称为堆对象。 √ 17.任何对象都可以使用delete运算符来释放。

× 18.使用new运算符创建的对象数组其元素都具有默认值。 √ 19.类的作用域范围指的是类体内。 × 20.对象的存储类只有外部的和静态的。

7.2 单选题

1.f1()函数是类A的公有成员函数,p是指向类的成员函数f1()的指针,下列表示中正确的是( C )。

A.p=f1() B.p=f1 C.p=A::f1 D.p=A::f1()

2.p是指向类A数据成员a的指针,a是类A的一个对象。在给a成员赋值为5的下列表达式中,正确的是( C )。

A.a.p=5 B.a->p=5 C.a.*p=5 D.*a.p=5

3.Void Set(A&a);是类A中一个成员函数的说明,其中A&a的含义是( A )。 A.类A的对象引用a作该函数的参数 B.类A的对象a的地址值作函数的参数 C.表达式变量A与变量a按位与作函数参数 D.指向类A对象指针a作函数参数

4.已知:const A a;其中A是一个类名,指向常对象指针的表示为( D )。 A.const * A pa; B.const A *pa; C.A * const pa; D.const *pa A; 5.下列关于子对象的描述中,错误的是( D )。 A.子对象不可以是自身类的对象 B.子对象是另一个类的对象

10

C.子对象的初始化要包含在构造函数中 D.一个类中只能有一个子对象 6.执行下列说明语句,其调用构造函数的次数为( A )。

A a[5],*p[2];其中,A是一个类名

A.5 B.6 C.7 D.10 7.下列关于运算符new的描述中,错误的是( D )。 A.它可以创建对象或变量

B.它可以创建对象数组或一般类型数组

C.用它创建对象或对象数组时要调用相应的构造函数 D.用它创建的对象可以不用delete运算符释放

8.下列关于运算符delete的描述中,错误的是( B )。

A.使用该运算符可以释放用new运算符创建的对象或对象数组 B.使用该运算符可以释放所有对象

C.使用delete运算符时会自动调用析构函数

D.用它释放对象数组时,它作用的指针名前要加下标运算符[ ] 9.定义不同存储类对象时,必须要加的存储类说明符是( C )。 A.auto B.extern C.statie D.register 10.下列关于this的描述中,错误的是( D )。

A.this是一个由系统自动生成的指针 B.this指针是指向对象的

C.this指针在用对象引用成员函数时系统创建的 D.this指针只能隐含使用,不能显式使用

7.3 填空题

已知:class A{ public:A (int i) { a=i;}

void print( ) { cont<

要求:

1.定义一个指向对象的常指针p,应该是 A *const p; 。 2.定义一个指向常对象指针p,应该是 A const *p; 。

3.定义类A的含有5个元素的一维对象数组a,应该是 A a[5]; 。

4.定义一个对象指针数组pa,它有5个元素,每个元素是类A对象指针,应该是 A *pa[5]; 。 5.使用new创建一个堆对象,一个实参值为5,应该是 A *p; p=new A(5); 。

6.使用new创建一个对象数组,该数组用指针pa指向,并使数组的3个元素都是类A的对象a1的值。应该是 A a1,*pa; pa=new A[3]; pa[0]=pa[1]=pa[2]=a1; 。

7.在某个函数体内定义一个静态类的对象sa,应该是 static A sa; 。

8.定义一个类A的对象a1,并给它赋值,其实参值为8,应该是 A a1(8); 。

7.4 分析下列程序的输出结果 1.

#include class A { public: A(int i) { a=i; }

11

A() { a=0;

cout<<\ } ~A()

{ cout<<\ } void Print()

{ cout<

A a[4],*p; int n=1; p=a;

for(int i=0;i<4;i++) a[i]=A(++n); for(i=0;i<4;i++) (p+i)->Print(); }

答: Default constructor called. 0 Default constructor called. 0 Default constructor called. 0 Default constructor called. 0 Destructor called. 2 Destructor called. 3 Destructor called. 4 Destructor called. 5 2 3 4 5

Destructor called. 5 Destructor called. 4 Destructor called. 3 Destructor called. 2

2.

#include class B {

public:

12

B(int i) { b=i; } B() {

b=0;

cout<<\ } ~B()

{ cout<<\ } void Print()

{ cout<

B *pb[4]; int n=1;

for(int i=0;i<4;i++) pb[i]=new B(n++); for(i=0;i<4;i++) pb[i]->Print(); for(i=0;i<4;i++) delete *(pb+i); } 答: 1 2 3 4

Destructor called. 1 Destructor called. 2 Destructor called. 3 Destructor called. 4

3.

#include class C { public: C(int i) { c=i; } C() { c=0;

cout<<\ }

13

~C()

{ cout<<\ } void Print()

{ cout<

void main() {

C *p;

p=new C[4]; int n=1;

for(int i=0;i<4;i++) p[i]=C(n++); for(i=0;i<4;i++) p[i].Print(); delete []p; }

答: Default constructor called. 0 Default constructor called. 0 Default constructor called. 0 Default constructor called. 0 Destructor called. 2 Destructor called. 3 Destructor called. 4 Destructor called. 5 2 3 4 5

Destructor called. 5 Destructor called. 4 Destructor called. 3 Destructor called. 2

4.

#include class D { public: D() {

d1=d2=0;

cout<<\ }

D(int i,int j) {

14

d1=i; d2=j;

cout<<\ } ~D()

{ cout<<\ } void Set(int i,int j) { d1=i;d2=j; } private: int d1,d2;

};

void main() {

int n(10),m(20);

D d[4]={D(5,7),D(3,6),D(7,9),D(1,4)}; for(int i=0;i<4;i++) d[i].Set(n++,m++); }

答: Constructor called. d1=5,d2=7 Constructor called. d1=3,d2=6 Constructor called. d1=7,d2=9 Constructor called. d1=1,d2=4 Destructor called. d1=13,d2=23 Destructor called. d1=12,d2=22 Destructor called. d1=11,d2=21 Destructor called. d1=10,d2=20

5.

#include class E {

public:

E(int i,int j) {

e1=i; e2=j;

cout<<\ }

void FunE(E *e) {

e1=e->e1; e2=e->e2;

cout<<\ }

void FunE(E &e) {

e1=e.e1; e2=e.e2;

cout<<\ } private:

15

int e1,e2; }; void main() {

E a(5,6),b(3,4); a.FunE(&b); b.FunE(a); }

答: Constructor called. e1=5,d2=6 Constructor called. e1=3,e2=4 In FunE(E &e). e1=3,e2=4 In FunE(E &e). e1=3,e2=4

6.

#include class F {

public:

class G {

public: G() {} G(int i) { g=i; } int GetValue() { return g; } void Print(F *p); private: int g; }myg;

friend class G; F(int i,int j):myg(i) { f=j; } private: int f; };

void F::G::Print(F *p) {

cout<f<

void main() {

F::G g; F f(5,10);

f.myg.Print(&f); g=f.myg;

cout<

7.5 编程题

1.按下列要求实现一个栈类的操作。该类名为Stack,包括如下操作:

16

(1)压栈操作:Push(); (2)弹栈操作:Pop();

(3)获取栈顶元素:Peer(); (4)判栈空操作:IsEmpty(); (5)判栈满操作:IsPull()。 设栈最多可存放50个整数。 栈中成员用数组表示。

编写一个程序,定义一个栈类的对象数组来验证该类操作。 答:栈的正常操作程序如下: #include #include class Stack {

public:

Stack(int i); ~Stack() { delete [] sta; } void Push(int i); int Pop(); void IsUpll() { if(tos==length) { cout<<\ return; } } int IsEmpty() { if(tos==0) { cout<<\ return 0; } } private: int *sta;; int tos,length; }; Stack::Stack(int i) { sta=new int[i]; if(!sta) { cout<<\ abort(); } tos=0; length=i; } void Stack::Push(int i) {

17

sta[tos]=i; tos++; } int Stack::Pop() { tos--; return sta[tos]; }

void main() { Stack a(50); a.Push(1); a.Push(2); a.Push(3); a.Push(4); a.Push(5); a.Push(6); a.Push(7); a.Push(8); a.Push(9); a.Push(10); cout<

判断栈的空、满操作,请读者修改上述程序。

2.按下列要求实现一个有关学生成绩的操作。 该类名为Student。

(1)每个学生的信息包含有姓名(字符数组)和成绩(int型)。 (2)共有5个学生,用对象数组表示。

(3)计算出5个学生中的最高分,并输出姓名及分数。 答:编程如下:

#include #include class Student {

public:

Student(char s[],int gr)

{ strcpy(name,s); grade=gr; } friend void fun(); private:

char name[10]; int grade; };

18

}

void main() { fun(); }

3.按如下要求编程验证子对象的有关操作。 (1)定义两个类A和类B。

(2)在类B中有两个类A的对象one,two。 验证如下事实:

(1)在类B的构造函数中应该包含对两个类A的子对象的初始化项,被放在成员初始化列表中。

(2)在类B的默认构造函数中隐含着子对象的初始化项。 (3)在类B的析构函数中也隐含着子对象的析构函数。 (4)调用子对象构造函数的顺序。

答:运行下列程序,从输出结果中分析要验证的4个事实。 程序内容如下:

#include class A {

public: A() { cout<<\ } A(int i) { a=i; cout<<\ ~A() { cout<<\ } int a; }; class B {

public: B() { cout<<\ } B(int i,int j,int k):two(j),one(k) { b=i; cout<<\ } void Print() { cout<

Student ss[5]={Student(\马力\王欣\李明\

Student(\赵亮\张京\

void fun() { int k=0; for(int i=0;i<5;i++) if(ss[i].grade>ss[0].grade) k=i; cout<<\最高分的学生姓名和成绩如下: \\n\

19

{ cout<<\ } private: int b; A one,two; };

void main() { cout<<\构造函数的调用情况:\\n\ static B bb0; B bb(1,2,3); cout<<\输出对象bb的数据成员值:\\n\ bb.Print(); cout<<\析构函数的调用情况:\\n\ }

7.6 简单回答下列问题

1. 对象指针可以指向一个有名对象,它可以指向一个无名对象吗?如何实现?

答:对象指针可以指向一个有名对象,也可以指向一个无名对象。例如,对象指针指向堆对象就是一个例子。假定己知类A,定义该类对象指针pa:

A *pa;

pa=new A(8);

pa就是一个指向类A的无名对象的指针。

2. 对象数组和对象指针数组的区别在哪里?

答:对象数组的元素是同一个类的若干个对象,对象指针数组的元素是指向同一个类的若干个对象指针。

3. 在一个类中定义了多个子对象,其构造函数调用子对象的构造函数的顺序取决于什么? 答:构造函数调用子对象的顺序取决于定义子对象的顺序,而与构造函数的成员初始化列表中给出的子对象速设无关。

4. 使用new运算符创建的对象,如果不使用delete运算符释放,它们会在生存期到了时

被系统释放吗? 答:不会。

5. 对象指针与对象引用作函数参数时具有相同的特点,为什么人们更喜欢使用对象引用

作函数参数呢?

答:因为使用对象引用比使用对象指针更简单。

第8章 继承性和派生类

练习题8

8.1 判断题

× 1.派生类只继承基类中的公有成员和保护成员,而不继承私有成员。 × 2.多重继承是指一个基类派生出多个派生类的情况。

20

√ 3.单重继承是指派生类只有一个基类的情况。 √ 4.派生类还可以作基类派生出新的派生类。

√ 5.派生类中成员的访问权限与基类的继承方式有关。

× 6.派生类中只包含直接基类的成员,不包含间接基类的成员。

√ 7.继承反映了类之间“是”的关系,组合反映了类之间“有”的关系。 × 8.基类中成员在派生类中都是可以访问的。

× 9.私有继承中基类的私有成员在派生类中还是私有的。

√ 10.保护继承方式下基类的保护成员在派生类仍是保护成员。

× 11.派生类的对象和派生类的派生类对派生类成员的访问权限是一样的。 √ 12.派生类的构造函数包含着直接基类的构造函数。

× 13.派生类的默认构造函数不包含有直接基类的构造函数。 × 14.派生类的析构函数中不包含直接基类的析构函数。 × 15.派生类是基类的子类型。

× 16.如果一个类是另一个类的子类型,则这个类的对象可以给另一个类的对象赋值,反之亦然。

√ 17.多重继承派生类的构造函数中应包含所有直接基类的构造函数。 × 18.多重继承的派生类构造函数中执行基类构造函数的顺序取决于该派生类构造函数的成员初始化列表中出现基类初始化项的顺序。

8.2 单选题

1.下列关于继承的描述中,错误的是( B )。 A.继承是重用性的重要机制

B.C++语言支持单重继承和双重继承 C.继承关系不是可逆的

D.继承是面向对象程序设计语言的重要特性

2.下列关于基类和派生类的描述中,错误的是( C )。 A.一个基类可以生成多个派生类

B.基类中所有成员都是它的派生类的成员 C.基类中成员访问权限继承到派生类中不变

D.派生类中除了继承的基类成员还有自己的成员 3.下列关于派生类的描述中,错误的是( D )。 A.派生类至少有一个基类

B.一个派生类可以作另一个派生类的基类

C.派生类的构造函数中应包含直接基类的构造函数 D.派生类默认的继承方式是public

4.派生类的对象可以直接访问的基类成员是( A )。 A.公有继承的公有成员 B.保护继承的公有成员 C.私有继承的公有成员 D.公有继承的保护成员 5.下列描述中,错误的是( D )。

A.基类的protected成员在public派生类中仍然是protected成员 B.基类的private成员在public派生类中是不可访问的 C.基类public成员在private派生类中是private成员 D.基类public成员在protected派生类中仍是public成员

6.派生类构造函数的成员初始化列表中,不能包含的初始化项是( B )。 A.基类的构造函数 B.基类的子对象 C.派生类的子对象 D.派生类自身的数据成员 7.下列关于子类型的描述中,错误的是( B )。 A.在公有继承下,派生类是基类的子类型

21

B.如果类A是类B的子类型,则类B也是类A的子类型 C.如果类A是类B的子类型,则类A的对象就是类B的对象 D.在公有继承下,派生类对象可以初始化基类的对象引用 8.下列关于多继承二义性的描述中,错误的是( D )。

A.一个派生类的多个基类中出现了同名成员时,派生类对同名成员的访问可能出现二

义性

B.一个派生类有多个基类,而这些基类又有一个共同的基类,派生类访问公共基类成

员时,可能出现二义性

C.解决二义性的方法是采用类名限定

D.基类和派生类中同时出现同名成员时,会产生二义性

8.3 填空题

1.继承的3种方式是 公有 、 私有 和 保护 。

2.如果类A继承了类B,则类A被称为 派生 类,类B被称为 基 类。

3.在保护继承方式下,基类的public成员成为派生类的 保护 成员,基类的protected成员成为派生类的 保护 成员。

4.当一个派生类中含有子对象时,该派生类的析构函数中应包含 直接基类 的析构函数、 子对象类的 析构函数和 自身类 的析构函数。

5.派生类的构造函数的成员初始化列表中可以包含的初始化项有 基类的构造函数 、 子对象类的构造函数 、 常数据成员 和 派生类其他非静态数据成员 。

8.4 分析下列程序的输出结果 1.

#include class A {

public:

A(int i,int j)

{ a1=i;a2=j; } void Move(int x,int y) { a1+=x;a2+=y; } void Print()

{ cout<<'('<

class B:private A {

public:

B(int i,int j,int k,int l):A(i,j) { b1=k;b2=l; } void Print()

{ cout<

{ A::Print(); } void fun()

{ Move(5,8); } private: int b1,b2; };

void main() {

A a(11,12); a.Print();

B b(31,32,33,34); b.fun();

22

b.Print(); b.f(); }

答: (11,12) 33.34 (36,40)

2.

#include class A {

public:

void InitA(int i,int j) { a1=i;a2=j; } void Move(int x,int y) { a1+=x;a2+=y; } int Geta1()

{ return a1; } int Geta2()

{ return a2; } private: int a1,a2; };

class B:public A {

public:

void InitB(int i,int j,int k,int l) {

InitA(i,j); b1=k; b2=l; }

void Move(int x,int y) { b1+=x;b2+=y; } int Getb1()

{ return b1; } int Getb2()

{ return b2; } private: int b1,b2; };

class C:public B {

public:

void fun()

{ Move(10,15); } }; void main() { C c;

c.InitB(11,12,13,14); c.fun();

cout<

答: 11,12,23,29

3.

23

#include class A { public: A(int i):a(i)

{ cout<<\ } ~A()

{ cout<<\ } void Print()

{ cout<

class B:public A { public:

B(int i=0,int j=0):A(i),a(j),b(i+j) { cout<<\ } ~B()

{ cout<<\ } void Print() {

A::Print();

cout< B b1(8),b2(12,15); b1.Print(); b2.Print(); }

答: A:constructor called. A:constructor called. B:Constructor called. A:constructor called. A:constructor called.

24

B:Constructor called. 8 8,0 12 27,15

B:Destructor called. A:Destructor called. A:Destructor called. B:Destructor called. A:Destructor called. A:Destructor called.

4.

#include class A { public: A(int i)

{ cout<<\ } ~A()

{ cout<<\ } }; class B { public: B(int i)

{ cout<<\ } ~B()

{ cout<<\ } }; class C { public: C(int i)

{ cout<<\ } ~C()

{ cout<<\ } };

class D:public A,public B,public C { public:

D(int i,int j,int k,int l):A(i),B(j),C(k),a(l)

25

{ cout<<\ } ~D()

{ cout<<\ private: A a; };

void main() {

D d(3,4,5,6); }

答: Constructor in A. 3 Constructor in B. 4 Constructor in C. 5 Constructor in A. 6 Constructor in D. 6 Destructor in D. Destructor in A. Destructor in C. Destructor in B. Destructor in A.

8.5 编程题

1.按下列要求编程:按照右边图中所示的各类的关系,编程输出它们的信息。各类中的数据成员如下:

Person: char *name(姓名),*dept(系别) Student: char *grade(年级) Teacher: char *lesson(授课名)

Student Teacher(在职读研): char *major(专业方向)

Person Student Teacher Student Teacher

答: 编程如下:

#include #include class Person { public: Person(char *s) { name=new char[strlen(s)+1]; strcpy(name,s); } void Print() { cout<<\姓名: \ } protected: char *name;

26

}; class Student:virtual public Person { public: Student(char *s,char *t):Person(s) { grad=new char[strlen(t)+1]; strcpy(grad,t); } void Print() { Person::Print(); cout<<\年级: \ } protected: char *grad; }; class Teacher:virtual public Person { public: Teacher(char *s,char *t):Person(s) { lesson=new char[strlen(t)+1]; strcpy(lesson,t); } void Print() { Person::Print(); cout<<\授课名: \ } protected: char *lesson; }; class StudentTeacher:public Student,public Teacher { public: StudentTeacher(char *p,char *q,char *r,char *s):Student(p,q),Teacher(p,r),Person(p) { Major=new char[strlen(s)+1]; strcpy(Major,s); } void Print() { Student::Print(); cout<<\专业方向:\ } protected: char *Major; };

void main() { Student stu(\马宁\级\

27

Teacher tea(\王新\高等代数\ StudentTeacher stutea(\刘力\级\数据结构\计算机软件\ stu.Print(); tea.Print(); stutea.Print();

}

2.设计一个程序,一行是信息,下一行画线,所画的线与信息行同长。例如,

C++ Programming

答: 编程如下:

#include #include class Line { public: Line(int i) { length=i; } void Show() { for(int i=0;i

28

void main() { MsgLine string1(\ string1.Show(); MsgLine string2(\ string2.Show(); }

8.6 简单回答下列问题

1. 在继承关系中,派生类中包含基类所有成员,基类是否也包含派生类的部分成员? 答:不包含。

2. 构造函数不能继承,派生类的构造函数中是否应包含直接基类的构造函数和所有间接

基类的构造函数?

签:派生类的构造函数中只包含直接基类的构造函数。

3. 派生类的析构函数中不包含直接基类的析构函数,对吗? 答:不对。

4. 派生类的对象可以给基类对象赋值吗?

答:一般情况下不可以,只有在公有继承的情况下可以。

5. 多重继承的二义性可以避免吗? 答:可以避免,通常使用类名限定。

第9章 多态性和虚函数

练习题9

9.1 判断题

√ 1.运算符重载是通过对已有的运算符重新定义操作功能来实现的,它是C++语言多态性的一种表现。

√ 2.所有的运算符都可以重载。

√ 3.运算符重载只可以是类的成员函数和友元函数,不可以是普通函数。

√ 4.运算符重载是通过函数来实现的,定义运算符重载函数时,函数名中要使用关键字operator。

√ 5.用于类对象的运算符中只有取地址运算符(&)有默认的可以使用。 √ 6.运算符重载后,优先级、结合性和操作数都是不变的。 √ 7.重载运算符的函数也可以设置默认参数。 √ 8.使用成员函数方法和使用友元函数的方法所定义的重载运算符函数的参数个数是不相同的。

√ 9.静态联编和动态联编都是在编译时进行的,二者的区别仅是前者对非虚函数,后者对虚函数。

√ 10.只要是成员函数就可以说明为虚函数,因为虚函数是一种成员函数。

√ 11.虚函数有继承性,基类中说明的虚函数只要在它的派生类中与它名字相同的,一定是虚函数。

√ 12.虚函数可以被类的对象调用,也可以被类的对象指针和对象引用调用。

29

√ 13.动态联编指的是在运行期间来选择不同类的虚函数。 √ 14.虚函数是实现动态联编的充分必要条件。

√ 15.含有纯虚函数的类称为抽象类,与抽象类相对应的是具体类。 √ 16.抽象类可以定义对象,不可以定义对象指针和对象引用。 √ 17.成员函数和构造函数调用虚函数都可以实现动态联编。

√ 18.析构函数可以说明为虚函数,而构造函数说明为虚函数没有意义。 √ 19.抽象类的派生类一定是具体类。

√ 20.一个抽象类中可以包含有多个纯虚函数,一个派生类中也可以包含多个虚函数。 9.2 单选题

1.下列运算符中,不可以重载的是( D )。 A.&& B.& C.[ ] D.?:

2.下列关于运算符重载的描述中,错误的是( B )。 A.运算符重载不改变优先级

B.运算符重载后,原来运算符操作不可再用 C.运算符重载不改变结合性

D.运算符重载函数的参数个数与重载方式有关

3.下列关键字中,用来说明虚函数的关键字是( C )。 A.inline B.operator C.virtual D.public 4.下列的成员函数中,纯虚函数是( A )。 A.virtual void f1() = 0 B.void f1() = 0; C.virtual void f1() {} D.virtual void f1() == 0; 5.含有一个或多个纯虚函数的类称为( A )。 A.抽象类 B.具体类 C.虚基类 D.派生类 6.下列关于虚函数的描述中,错误的是( C )。 A.虚函数是一个成员函数 B.虚函数具有继承性

C.静态成员函数可以说明为虚函数

D.在类的继承的层次结构中,虚函数是说明相同的函数 7.下列各种类中,不能定义对象的类是( B )。 A.派生类 B.抽象类 C.嵌套类 D.虚基类 8.下列关于抽象类的描述中,错误的是( D )。

A.抽象类中至少应该有一个纯虚函数 B.抽象类可以定义对象指针和对象引用 C.抽象类通常用作类族中最顶层的类 D.抽象类的派生类必定是具体类

9.一个类的层次结构中,定义有虚函数,并且都是公有继承,在下列情况下,实现动态联编的是( D )。

A.使用类的对象调用虚函数

B.使用类名限定调用虚函数,其格式如下:<类名>::<虚函数名> C.使用构造函数调用虚函数 D.使用成员函数调用虚函数

10.下列关于动态联编的描述中,错误的是( C )。

A.动态联编是函数联编的一种方式,它是在运行时来选择联编函数的 B.动态联编又可称为动态多态性,它是C++语言中多态性的一种重要形式 C.函数重载和运算符重载都属于动态联编

30

D.动态联编只是用来选择虚函数的

9.3 填空题

1.C++语言多态性主要表现在动态联编、 函数 重载和 运算符 重载。 2.运算符重载函数的两种主要方式是 成员 函数和 友元 函数。

3.静态联编支持的多态性称为 静态 多态性,它是在 编译 时进行的;动态联编支持的多态性称为 动态 多态性,它是在 运行 时进行的。

4.虚函数是一种 非静态 成员函数。说明方法是在函数名前加关键字 virtual 。虚函数具有 继承 性,在基类中被说明的虚函数,具有相同说明的函数在派生类中自然是虚函数。

6. 含有 纯虚函数 的类称为抽象类。它不能定义对象,但可以定义 对象指针和 对象引用 。

9.4 分析下列程序的输出结果 1.

#include class Matrix {

public:

Matrix(int r,int c) {

row=r; col=c;

elem=new double[row*col]; }

double & operator ()(int x,int y) { return elem[x*col+y]; } ~Matrix()

{ delete []elem; } void print(int i)

{ cout<

double *elem; int row,col; };

void main() {

Matrix m(3,4); for(int i=0;i<3;i++) for(int j=0;j<4;j++) m(i,j)=4*i+j; for(i=0;i<3;i++)

for(int j=0;j<4;j++) {

m.print(4*i+j); cout<<\ \ }

cout<

答: 0 1 2 3 4 5 6 7 8 9 10 11

2.

#include class A {

public:

virtual void fun()

{ cout<<\ } };

31

class B:public A {

void fun()

{ cout<<\ } };

void ffun(A *pa) {

pa->fun(); }

void main() {

A *pa=new A; ffun(pa);

B *pb=new B; ffun(pb); }

答: A::fun() called. B::fun() called.

3.

#include class A {

public: A()

{ ver='A'; } virtual void print()

{ cout<<\ } protected: char ver; };

class B1:public A {

public: B1(int i)

{ info=i;ver='B'; } void print()

{ cout<<\ private: int info; };

class B2:public A {

public: B2(int i)

{ info=i; } void print()

{ cout<<\ private: int info; };

class B3:public B1 {

public:

B3(int i):B1(i)

{ info=i;ver='C'; } void print()

{ cout<<\ private: int info; };

void print_info(A *pa)

32

} } } {

pa->print(); }

void main() {

A a;

B1 b1(14); B2 b2(88); B3 b3(65); print_info(&a); print_info(&b1); print_info(&b2); print_info(&b3); }

答: The A version A

The B1 info: 14 version B The B2 info: 88 version A The B3 info: 65 version C

4.

#include class B {

public:

virtual void fun1()

{ cout<<\ virtual void fun2()

{ cout<<\ void fun3()

{ cout<<\ void fun4()

{ cout<<\ };

class D:public B {

public:

void fun1()

{ cout<<\ void fun2()

{ cout<<\ void fun3()

{ cout<<\ void fun4()

{ cout<<\ };

void main() {

B *pb; D d; pb=&d; pb->fun1(); pb->fun2(); pb->fun3(); pb->fun4(); }

答: D::fun1(). D::fun2(). B::fun3(). B::fun4().

5.

} } } } 33

} } } } #include class A {

public: A()

{ cout<<\ } virtual ~A()

{ cout<<\ } virtual void f1()

{ cout<<\ } void f2() { f1(); } };

class B:public A {

public: B()

{ f1();cout<<\ } ~B()

{ cout<<\ } };

class C:public B {

public: C()

{ cout<<\ } ~C()

{ cout<<\ } void f1()

{ cout<<\ } };

void main() {

A *pa=new C; pa->f2(); delete pa; }

答: In A cons. In A f1(). In B cons. In C cons. In C f1(). In C des. In B des. In A des.

6.

#include class A {

public:

virtual void print()=0; };

class B:public A {

public:

void print()

{ cout<<\ } };

class C:public B {

34

public:

void print()

{ cout<<\ } };

void fun(A *pa) {

pa->print(); }

void main() {

A *pa; B b; C c; pa=&b; fun(pa); pa=&c; fun(pa); }

答: In B print(). In C print().

9.5 编程题

1. 编程求圆、圆内接正方形和圈外切正方形的面积和周长。要求使用抽象类。 答: 编程如下:

#include const double PI=3.1415; class Shape { public: Shape(double i) { r=i; } virtual void Area()=0; virtual void Perimeter()=0; protected: double r; }; class Circle:public Shape { public: Circle(double i):Shape(i) { } void Area() { cout<<\圆的面积是 \ } void Perimeter() { cout<<\圆的周长是 \ } }; class In_Square:public Shape { public: In_Square(double i):Shape(i) { } void Area() { cout<<\圆内接正方形的面积是 \ } void Perimeter() { cout<<\圆内接正方形的周长是 \ }

35

}; class Ex_Square:public Shape { public: Ex_Square(double i):Shape(i) { } void Area() { cout<<\圆外切正方形的面积是 \ } void Perimeter() { cout<<\圆外切正方形的周长是 \ } };

void main() { Shape *ps; ps=new Circle(8); ps->Area(); ps->Perimeter(); ps=new In_Square(8); ps->Area(); ps->Perimeter(); ps=new Ex_Square(8); ps->Area(); ps->Perimeter(); delete ps; }

2. 在类的多层次继承结构中,类之间哪些函数是按作用域规则处理的?哪些函数是按多

态性规则处理的?试编程说明之。

答:一般成员函数是按作用域规则处理的,虚函数是按多态性规则中的动态联编处理的。下列程序中有一般成员函数和虚函数。

#include class A {

public: void Print() { cout<<\ } virtual void fun() { cout<<\ } };

class B:public A {

public: void Print() { cout<<\ } virtual void fun() { cout<<\ } };

void text(A &a) { a.fun(); }

void main()

36

{

A a; B b; a.Print(); b.Print(); text(b); }

9.6 简单回答下列问题

1. 运算符重载使用成员函数方法和友元函数方法是否都可以?并且是没有区别的吗? 答: 两种方都法可以。有区别,参数个数不同。

2. 运算符重载实际上通过函数来重新定义运算符的功能,运算符重载的功能直接通过函

数调用是否可以? 答: 可以。

3. 多态性中对函数的选择从时间上来区分有哪两种方式?

答: 一种是在编译时选定函数,称静态联编方式,另一种是在运行时选定函数,称动态联编方式。

4. 有虚函数是否就一定是动态联编?非虚函数是否就一定是静态联编? 答: 不一定。一定是。

5. 在多层次的继承结构中,基类与派生类中存在着虚函数,这时调用虚函数就一定实现

动态联编吗? 答:不一定。

第10章 C++语言的输入/输出操作

练习题10

10.1 判断题

√ 1.C++语言提供的文件操作包含文本文件和二进制文件。 × 2.预定义的提取符和插入符不可以再重载。

√ 3.C++语言中的读写函数,不仅可用于标准文件,也可用于磁盘文件。

× 4.使用插入符输出一个字符串与使用write()成员函数输出一个字符串是没有差别的。 × 5.使用成员函数put()一次可写入一个字符串。

× 6.读取一个字符的成员函数get()是不可以带参数的。

√ 7.读取一行字符的成员函数getline()具有一个默认的参数值'\\n'。 × 8.使用read()成员函数一次只能读取一行字符。 √ 9.输出数据的默认对齐方式是右对齐。

√ 10.使用流对象的成员函数进行格式输出要比使用控制符进行格式输出复杂些,因为成员函数需要对象调用,而控制符可直接使用。

√ 11.在非标准文件操作中,应该先定义流对象,再打开文件,必须使用open()函数。 √ 12.关闭打开的文件时使用成员函数close(),该函数无参数。

√ 13.进行二进制文件操作时,在打开文件方式中增加ios::binary选项。

37

× 14.在定位文件的读/写指针的操作中,只能向增加字节数的方向移动,不能向减少字节数的方向移动。

√ 15.C++语言的文件操作中,既可以顺序读写,又可以随机读写。

× 16.读/写指针相关函数tellp()的返回值是一个long int型数,这表示当前读指针距文件尾的字节数。

√ 17.在文件操作中,通常使用打开文件的流对象的值来判断打开文件是否成功。 × 18.文件结束函数eof()返回值为0时,表示文件结束。 10.2 单选题

1.C++语言程序中进行文件操作时应包含的头文件是( A )。 A.fstream.h B.math.h C.stdlib.h D.strstrea.h

2.C++语言程序中进行字符串流操作时应包含的头文件是( D )。 A.fstream.h B.math.h C.stdlib.h D.strstrea.h

3.C++语言程序中使用控制符进行格式输出时应包含的头文件是( B )。 A.fstream.h B.iomanip.h C.math.h D.strstrea.h

4.下列各语句是输出字符'A'的,其中错误语句是( D )。 A.cout<<'A'; B.cout.put('A'); C.char ch='A';cout<

5.在ios类中提供的控制格式的标志位中,八进制形式的标志位是( C )。 A.hex B.dec C.oct D.basefield

6.在打开磁盘文件的访问方式常量中,用来以追加方式打开文件的是( C )。 A.in B.out C.ate D.app()

7.在下列读写函数中,进行写操作的函数是( C )。 A.get() B.read() C.put() D.getline()

8.已知文本文件abc.txt,以读方式打开,下列的操作中错误的是( D )。 A.fstream infile (\B.ifstream infile (\C.ofstream infile (\ D.fstream infile; infile.open(\9.已知:ifstream input;下列写出的语句中,将input流对象的读指针移到距当前位置后(文件尾方向)100个字节处的语句是( C )。

A.input.seekg(100,ios::beg); B.input.seekg(100,ios::cur); C.input.seekg(?100,ios::cur); D.input.seekg(100,ios::end);

10.3 填空题

1.在格式输出的标志字中,设置格式对齐位的有 left 、 right 和 internal 。 2.在格式输出中,设置和清除格式标志位的成员函数分别是 setf() 和 unsetf() 。 3.系统规定与标准设备对应的4个流对象是 cin 、 cout 、 cerr 和 clog 。 4.在控制符中,用来指定八进制、十进制和十六进制的控制符分别是 oct 、 dec 和 hex 。

5.在定位读/写指针的带有两个参数的函数中,表示相对位置方式的3个常量是 cur 、 beg 和 end 。

10.4 分析下列程序的输出结果

38

1.

#include #include void main() {

int a=234;

cout< cout< cout<

*****234ok

1.23457 ***1.235

2.

#include #include

ostream &out1(ostream &outs) {

outs.setf(ios::left);

outs<

void main() {

int a=123;

cout<

cout< 173#####

3.

#include #include void main() {

for(int i=1;i<6;i++)

cout<

答: WWWWWWWWW WWWWWWW WWWWW WWW W

4.

#include #include #include void main() {

39

fstream inf,outf;

outf.open(\ if(!outf) {

cout<<\ abort(); }

outf<<\ outf<<\ outf<<\ outf.close();

inf.open(\ if(!inf) {

cout<<\ abort(); }

char ch[80]; int a(1);

while(inf.getline(ch,sizeof(ch))) cout<

答: 1:abcdef 2:123456 3:ijklmn

5.

#include #include #include void main() {

fstream f;

f.open(\ if(!f) {

cout<<\ abort(); }

char ch[]=\ for(int i=0;i

while(f.get(c)) cout<

答: abcdefg1234567.

6.

#include #include #include struct student {

char name[20]; long int number; int totalscore;

}stu[5]={\

40

本文来源:https://www.bwwdw.com/article/re9.html

Top