第六章练习题
一、选择题
1.下列类的定义中正确的是( )。
(A)class a{int x=0;int y=1;} (B)class b{intx=0;int y=1;};
(C)class c{int x;inty;} (D)class d{int x;inty;};
2.若有以下说明,则在类外使用对象objX成员的正确语句是( )。
class X
{ int a;
voidfun1();
public:
voidfun2();
};
X objX;
(A)objX.a=0; (B)objX.fun1(); (C)objX.fun2(); (D)X::fun1();
3.在类定义的外部,可以被访问的成员有( )。
(A)所有类成员 (B)private或protected的类成员
(C)public的类成员 (D)public或private的类成员
4.下列关于类和对象的说法中,正确的是( )。
(A)编译器为每个类和类的对象分配内存 (B)类的对象具有成员函数的副本
(C)类的成员函数由类来调用 (D)编译器为每个对象的数据成员分配内存
5.关于this指针的说法正确的是( )。
(A)this指针必须显式说明 (B)定义一个类后,this指针就指向该类
(C)成员函数拥有this指针 (D)静态成员函数拥有this指针
【解答】 D D C D C
二、程序练习
1.阅读程序,写出运行结果。
#include<iostream>
using namespacestd;
class A
{ public :
int f1();
int f2();
void setx( int m ) { x =m; cout << x << endl; }
void sety( int n ) { y =n; cout << y << endl; }
int getx() { returnx; }
int gety() { returny; }
private :
int x, y;
};
int A::f1()
{ return x + y; }
int A::f2()
{ return x - y; }
int main()
{ A a;
a.setx( 10 ); a.sety( 5 );
cout << a.getx() << '\t'<< a.gety() << endl;
cout << a.f1() << '\t' <<a.f2() << endl;
}
【解答】
2.改写以下程序。要求定义类student,封装三个数据成员和两个成员函数intpt和output,使程序得到相同的运行效果。
#include<iostream>
using namespacestd;
struct student
{ char name[20];
unsignedint id;
doublescore;
};
void input(student&stu)
{ cout<<"name?";
cin>>stu.name;
cout<<"id?";
cin>>stu.id;
cout<<"score?";
cin>>stu.score;
}
voidoutput(student &stu)
{ cout<<"name:"<<stu.name<<"\tid:"<<stu.id<<"\tscore: "<<stu.score<<endl; }
int main()
{ student s={"\0", 0, 0};
input(s);
output(s);
}
【解答】
#include <iostream>
using namespacestd;
class student
{
char name[20];
unsigned int id;
double score;
public:
void input()
{
cout<<"name?";
cin>>name;
cout<<"id?";
cin>>id;
cout<<"score?";
cin>>score;
}
void output()
{
cout<<"name:"<<name<<"\tid: "<<id<<"\tscore:"<<score<<endl;
}
};
int main()
{
student s;
s.input();
s.output();
}
同步练习6.2
一、选择题
1.下面对构造函数的不正确描述是( )。
(A)用户定义的构造函数不是必须的 (B)构造函数可以重载
(C)构造函数可以有参数,也可以有返回值 (D)构造函数可以设置默认参数
2.下面对析构函数的正确描述是( )。
(A)系统在任何情况下都能正确析构对象 (B)用户必须定义类的析构函数
(C)析构函数没有参数,也没有返回值 (D)析构函数可以设置默认参数
3.构造函数是在( )时被执行的。
(A)建立源程序文件 (B)创建对象 (C)创建类 (D)程序编译时
4.在下列函数原型中,可以作为类Base析构函数的是( )。
(A)void~Base (B)~Base() (C)~Base()const (D)Base()
5.AB是一个类,那么执行语句“ABa (4), b[3], *p;”调用了( )次构造函数。
(A)2 (B)3 (C)4 (D)5
6.下面关于复制构造函数调用的时机,不正确的是( )调用。
(A)访问对象时 (B)对象初始化时
(C)函数具有类类型传值参数时 (D)函数返回类类型值时
7.说明一个类的对象时,系统自动调用( )。
(A)成员函数 (B)构造函数 (C)析构函数 (D)友元函数
8.程序中撤销一个类对象时,系统自动调用( )。
(A)成员函数 (B)构造函数 (C)析构函数 (D)友元函数
【解答】 C C B B C A B C
二、程序练习
1.阅读程序,写出运行结果。
#include<iostream>
using namespacestd;
class T
{ public :
T( int x, int y )
{ a = x; b = y;
cout << "调用构造函数1." << endl;
cout << a << '\t' << b<< endl;
}
T( T &d )
{ cout << "调用构造函数2." << endl;
cout << d.a << '\t' << d.b<< endl;
}
~T() { cout << "调用析构函数."<<endl; }
int add( int x, int y = 10 ) { returnx + y; }
private :
int a, b;
};
int main()
{ T d1( 4, 8 );
T d2( d1 );
cout << d2.add( 10 ) << endl;
}
【解答】
2.为同步练习6.1程序练习第2题中的student类增加一个构造函数,使得建立对象时可以完成用户指定数据的初始化。默认初始化值为:( "\0", 0, 0 )。
若主函数为:
int main()
{ student s1;
s1.output();
student s2("Zhangsan", 120, 85);
s2.output();
student s3;
s3.input();
s3.output();
}
将有以下屏幕对话和输出:
name: id: 0 score:0
name: Zhangsan id:120 score: 85
name? Lihua
score? 95
name: Lihua id: 130 score: 95
请补充student类的构造函数。
【解答】
class student
{
char name[20];
unsigned id;
double score;
public:
student(char s[20]="\0",unsigned k=0, double t=0)
{
strcpy_s(name,s);
id=k;
score=t;
}
void input()
{
cout<<"name?";
cin>>name;
cout<<"id?";
cin>>id;
cout<<"score?";
cin>>score;
}
void output()
{
cout<<"name:"<<name<<"\tid: "<<id<<"\tscore:"<<score<<endl;
}
};
一、选择题
1.在下列选项中,( )不是类的成员函数。
(A)构造函数 (B)析构函数 (C)友元函数 (D)复制构造函数
2.下面对友元的错误描述是( )。
(A)关键字friend用于声明友元
(B)一个类中的成员函数可以是另一个类的友元
(C)友元函数访问对象的成员不受访问特性影响
(D)友元函数通过this指针访问对象成员
3.已知类A是类B的友元,类B是类C的友元,则下面选项描述正确的是( )。
(A)类A一定是类C的友元
(B)类C一定是类A的友元
(C)类C的成员函数可以访问类B的对象的任何成员
(D)类A的成员函数可以访问类B的对象的任何成员
4.下述关于类的静态成员的特性中,描述错误的是( )。
(A)说明静态数据成员时前边要加修饰符static
(B)静态数据成员要在类体外定义
(C)引用静态数据成员时,要在静态数据成员前加<类名>和作用域运算符
(D)每个对象有自己的静态数据成员副本
5.若有以下说明,则对n的正确访问语句是( )。
class Y
{ //…;
public:
staticintn;
};
int Y::n;
Y objY;
(A)n=1; (B)Y::n=1; (C)objY::n=1; (D)Y->n
6.若有以下类Z说明,则函数fStatic中访问数据a错误的是( )。
class Z
{ static int a;
public:
staticvoid fStatic(Z&);
};
int Z::a=0; Z objZ;
(A)voidZ::fStatic() { objZ.a =1; }
(B)voidZ::fStatic() { a = 1; }
(C)voidZ::fStatic() { this->a = 0; }
(D)voidZ::fStatic() { Z::a = 0; }
7.若有以下类W说明,则函数fConst的正确定义是( )。
class W
{ int a;
public:
voidfConst(int&) const;
};
(A)void W::fConst(int&k )const { k = a; }
(B)void W::fConst(int&k )const { k = a++; }
(C)void W::fConst(int&k )const { cin>> a; }
(D)void W::fConst(int&k )const { a = k; }
8.若有以下类T说明,则函数fFriend的错误定义是( )。
class T
{ inti;
friendvoid fFriend( T&, int );
};
(A)void fFriend( T&objT, int k ) { objT.i = k; }
(B)void fFriend( T&objT, int k ) { k = objT.i; }
(C)void T::fFriend( T&objT, int k ) { k += objT.i; }
(D)void fFriend( T&objT, int k ) { objT.i += k; }
【解答】 C D D D B C A C
二、程序练习
1.阅读程序,写出运行结果。
#include<iostream>
using namespacestd;
class T
{ public:
T(intx) { a=x; b+=x; };
staticvoid display(T c) { cout<<"a="<<c.a<<'\t'<<"b="<<c.b<<endl; }
private:
int a;
staticint b;
};
int T::b=5;
int main()
{ T A(3), B(5);
T::display(A);
T::display(B);
}
【解答】
2.阅读程序,写出运行结果。
#include<iostream>
using namespacestd;
#include<cmath>
class Point
{ public :
Point( float x, float y )
{ a= x; b = y; cout<<"点( "<<a<<","<<b<<" )"; }
friend double d( Point &A, Point&B )
{ return sqrt((A.a-B.a)*(A.a-B.a)+(A.b-B.b)*(A.b-B.b)); }
private:
double a, b;
};
int main()
{ Point p1( 2, 3 );
cout<< " 到";
Pointp2( 4, 5 );
cout<< "的距离是:" << d( p1,p2 ) << endl;
}
【解答】
3.阅读程序,写出运行结果。
#include<iostream>
using namespacestd;
class A
{ public :
A() { a = 5; }
void printa() { cout << "A:a =" << a << endl; }
private :
int a;
friend class B;
};
class B
{ public:
voiddisplay1( A t )
{ t.a++; cout << "display1:a = "<< t.a << endl; };
voiddisplay2( A t )
{ t.a--; cout << "display2:a = " << t.a<< endl; };
};
int main()
{ A obj1;
Bobj2;
obj1.printa();
obj2.display1(obj1 );
obj2.display2(obj1 );
obj1.printa();
}
【解答】
4.为同步练习6.2程序练习第2题中的student类添加一个复制构造函数。若主函数为:
int main()
{ cout<<"s2:\n";
student s2("Zhangsan", 120, 85);
s2.output();
cout<<"s3:\n";
student s3(s2);
s3.output();
}
则运行结果如下:
s2:
name: Zhangsan id: 120 score: 85
s3:
name: Zhangsan id: 120 score: 85
【解答】
class student
{
char name[20];
unsigned id;
double score;
public:
student(char s[20]="\0",unsigned k=0, double t=0)
{
strcpy_s(name,s);
id=k;
score=t;
}
student(const student &ss) //复制构造函数
{
strcpy_s(name,ss.name);
id=ss.id;
score=ss.score;
}
void input()
{
cout<<"name?";
cin>>name;
cout<<"id?";
cin>>id;
cout<<"score?";
cin>>score;
}
void output()
{
cout<<"name:"<<name<<"\tid: "<<id<<"\tscore: "<<score<<endl;
}
};
5.修改同步练习6.1程序练习第2题中的student类,把input和output函数写为友元函数,并相应修改主函数,使程序得到正确的运行结果。
【解答】
#include<iostream>
#include<fstream>
using namespacestd;
class student
{
char name[20];
unsigned id;
double score;
public:
student(char s[20]="\0",unsigned k=0, double t=0)
{
strcpy_s(name,s);
id=k;
score=t;
}
student(const student &ss)
{
strcpy_s(name,ss.name);
id=ss.id;
score=ss.score;
}
friend void input(student&ss); //声明友元函数
friend void output(student ss); //声明友元函数
};
void input(student&ss)
{
cout<<"name? ";
cin>>ss.name;
cout<<"id? ";
cin>>ss.id;
cout<<"score? ";
cin>>ss.score;
}
voidoutput(student ss)
{
cout<<"name:"<<ss.name<<"\tid:"<<ss.id<<"\tscore: "<<ss.score<<endl;
}
int main()
{
student s1;
input(s1);
output(s1);
}
6.删除同步练习6.1程序练习第2题中student类的成员函数input和output,定义一个iostudent类,它是student类的友元类,完成对student数据成员的输入/输出操作。编写完整的程序,使其得到正确的运行效果。
【解答】
#include<iostream>
#include<fstream>
using namespacestd;
class student
{
char name[20];
unsigned id;
double score;
public:
student(char s[20]="\0",unsigned k=0, double t=0)
{
strcpy_s(name,s);
id=k;
score=t;
}
student(conststudent &ss)
{
strcpy_s(name,ss.name);
id=ss.id;
score=ss.score;
}
friend class iostudent;
};
class iostudent //定义iostudent类
{
public:
void input(student &ss)
{
cout<<"name?";
cin>>ss.name;
cout<<"id?";
cin>>ss.id;
cout<<"score?";
cin>>ss.score;
}
void output(student ss)
{
cout<<"name:"<<ss.name<<"\tid:"<<ss.id<<"\tscore: "<<ss.score<<endl;
}
};
int main()
{
student s1;
iostudent io;
io.input(s1);
io.output(s1);
}
同步练习6.4
一、选择题
1.若classB中定义了一个classA的类成员A a,则关于类成员的正确描述是( )。
(A)在类B的成员函数中可以访问A类的私有数据成员
(B)在类B的成员函数中可以访问A类的保护数据成员
(C)类B的构造函数可以调用类A的构造函数进行数据成员初始化
(D)类A的构造函数可以调用类B的构造函数进行数据成员初始化
2.下列关于类的包含描述正确的是( )。
(A)可以使用赋值语句对对象成员进行初始化
(B)可以使用“参数初始式”调用成员类的构造函数初始化对象成员
(C)被包含类可以访问包含类的成员
(D)首先执行自身构造函数,再调用成员类的构造函数
【解答】 C B
二、程序练习
1.阅读程序,写出运行结果。
#include<iostream>
using namespacestd;
class A
{ public:
A(int x=0):a(x){ }
void getA(int A) { a =A; }
void printA() {cout<<"a="<<a<<endl; }
private:
int a;
};
class B
{ public:
B(int x=0, int y=0):aa(x) { b = y; }
void getAB(int A, int outB) { aa.getA(A); b=outB; }
void printAB() { aa.printA();cout<<"b="<<b<<endl; }
private:
A aa;
int b;
};
int main()
{ A objA;
int m=5;
objA.getA(m);
cout<<"objA.a="<<m<<endl;
cout<<"objB:\n";
B objB;
objB.getAB(12,56);
objB.printAB();
}
【解答】
2.为同步练习6.1程序练习第2题中的student类添加一个date类数据成员birthday,date类包含三个数据成员:year、month、day,以及用于初始化的构造函数,用于输入数据的input和输出数据的output成员函数。student类构造函数需要完成birthday的数据初始化,并且完成birthday数据的输入/输出。用main函数测试这个类。
【解答】
#include <iostream>
#include<fstream>
using namespace std;
class date //定义date类
{
intyear, month, day;
public:
date(inty, int m, int d)
{
year=y;
month=m;
day=d;
}
voidinput()
{
cout<<"birthof year ? ";
cin>>year;
cout<<"\tmonth? ";
cin>>month;
cout<<"\t day ? ";
cin>>day;
}
voidoutput()
{
cout<<"birth:"<<year<<"-"<<month<<"-"<<day<<endl;
}
};
class student //定义student类
{
charname[20];
unsignedid;
doublescore;
datebirth; //date类的数据成员
public:
//构造函数
student(chars[20]="No name", unsigned k=0, double t=0, int y=2000, int m=1, intd=1)
: birth(y, m, d)
{
strcpy_s(name,s);
id=k;
score=t;
}
voidinput()
{
cout<<"name?";
cin>>name;
birth.input();
cout<<"id?";
cin>>id;
cout<<"score?";
cin>>score;
}
voidoutput()
{
cout<<"name:"<<name<<"\t";
birth.output();
cout<<"id:"<<id<<"\tscore: "<<score<<endl;
}
};
int main()
{
students;
s.input();
s.output();
}
综合练习
一、思考题
1.结构与类有什么区别?如果把程序中定义结构的关键字struct直接改成class,会有什么问题?用教材中的一个例程试试看,想一想做什么修改能使程序正确运行?
【解答】
结构是数据的封装,类是数据和操作的封装。可以把结构看成是类的特例。结构和类都可以用关键字struct或class定义。区别是,struct定义的结构或类的全部成员都是公有的,用class定义的结构或类不做声明的成员是私有的。
若把struct改成class,只需要把全部成员定义为public就可以了。
2.有说明:
class A
{
int a;
double x;
public:
funMember();
};
A a1, a2, a3;
编译器为对象a1、a2和a3开辟了什么内存空间?它们有各自的funMember函数的副本吗?C++通过什么机制调用类的成员函数?
【解答】
开辟的存储空间有a1.a,a1.x, a2.a, a2.x, a3.a, a3.x。各对象没有funMember函数的副本,C++通过this指针调用成员函数。
3.C++提供了系统版本的构造函数,为什么还需要用户自定义构造函数?编写一个验证程序,说明自定义构造函数的必要性。
【解答】
类的默认构造函数可以建立基本类型数据成员的存储空间。基于以下两个原因,需要用户定义构造函数:
(1)对数据成员的值做指定初始化;
(2)类的数据是由指针管理的堆。
程序略。
4.试从定义方式、访问方式、存储性质和作用域4个方面来分析类的一般数据成员和静态数据成员的区别,并编写一个简单程序验证它。
【解答】
| 定义方式 | 访问方式 | 存储性质 | 作用域 |
一般数据成员 | 类中定义 | 对象.数据成员 | 局部数据 | 由访问属性public, protected, private决定 |
静态数据成员 | 类中声明,类外定义 | 对象.数据成员 类::数据成员 | 全局数据 |
程序略。
5.试从定义方式、调用方式两个方面来分析常成员函数、静态成员函数和友元函数的区别。考察例6-16,若class Goods的指针域:
Goods * next;
被声明为私有(private)成员,程序会出现什么错误?做什么最小修改能使程序正确运行?
【解答】
| 定义方式 | 调用方式 |
常成员函数 | 函数原型以const做后缀 this指针被约束为指向常量的常指针 | 与一般成员函数调用形式相同 对数据成员只读 |
静态成员函数 | 以static做函数原型前缀 没有this指针 | 通过类或对象调用 用于操作静态数据成员 |
友员函数 | 以friend做函数原型前缀 没有this指针 | 通过参数访问对象 可以访问对象的不同属性的成员 |
在例6-16中,若把next声明为私有数据成员,只须把有关指针操作的函数定义为友员函数就可以了:
friendvoid purchase( Goods * &f, Goods *& r, int w );
friend void sale( Goods * & f ,Goods * & r );
6.设有:
class M
{ public: int a;
};
class N
{ public:
M m;
int b;
void fun()
{ /*…*/ }
};
int main()
{ N n;
N *p = &n;
/*…*/
}
描述在N::fun中如何访问M类的数据成员a?在main函数中又如何访问对象n的全部数据成员?
【解答】
在N::fun中访问M类的数据成员a的形式是: m.a
在main函数中访问M类的数据成员的形式是: n.b,n.m.a
二、程序设计
1.定义一个Book(图书)类,在该类定义中包括以下数据成员和成员函数。
数据成员:bookname(书名)、price(价格)和number(存书数量)。
成员函数:display()显示图书的情况;borrow()将存书数量减1,并显示当前存书数量;restore()将存书数量加1,并显示当前存书数量。
在main函数中,要求创建某一种图书对象,并对该图书进行简单的显示、借阅和归还管理。
【解答】
#include <iostream>
using namespace std;
classBook
{
public:
void setBook(char*,double,int);
void borrow();
void restore();
void display();
private:
char bookname[40];
double price;
intnumber;
};
//在类外定义Book类的成员函数
voidBook::setBook(char *name, double pri, int num)
{
strcpy_s(bookname, name);
price=pri;
number=num;
}
voidBook::borrow()
{
if (number==0 )
{
cout<< "已没存书,退出!"<< endl;
abort();
}
number = number - 1;
cout << "借一次,现存书量为:"<< number << endl;
}
voidBook::restore()
{
number = number + 1;
cout << "还一次,现存书量为:"<< number << endl;
}
voidBook::display()
{
cout<< "存书情况:"<< endl
<< "bookname:" <<bookname << endl
<< "price:" <<price << endl
<< "number:" <<number << endl;
}
intmain()
{
char flag, ch;
Book computer;
computer.setBook( "C++程序设计基础", 32, 1000 );
computer.display();
ch = 'y';
while ( ch == 'y' )
{
cout << "请输入借阅或归还标志(b/r):";
cin >> flag;
switch ( flag )
{
case 'b': computer.borrow(); break;
case 'r': computer.restore();
}
cout << "是否继续?(y/n)";
cin>> ch;
}
computer.display();
}
2.定义一个Box(盒子)类,在该类定义中包括以下数据成员和成员函数。
数据成员:length(长)、width(宽)和height(高)。
成员函数:构造函数Box,设置盒子的长、宽和高三个初始数据;成员函数setBox对数据成员置值;成员函数volume计算盒子的体积。
在main函数中,要求创建Box对象,输入长、宽、高,输出盒子的体积。
【解答】
#include<iostream>
using namespacestd;
class BOX
{
public:
BOX( double l, double w, double h )
{ length = l;
width = w;
height = h;
}
void volume()
{ cout << "volume=" << length * width * height<< endl;
}
private:
double length, width, height;
};
int main()
{
BOX box1( 1,3,5 );
box1.volume();
BOX box2( 2,4,6 );
box2.volume();
}
3.定义一个student类,在该类定义中包括:一个数据成员(分数score)及两个静态数据成员(总分total和学生人数count);成员函数scoretotalcount(doubles) 用于设置分数、求总分和累计学生人数;静态成员函数sum()用于返回总分;静态成员函数average()用于求平均值。
在main函数中,输入某班同学的成绩,并调用上述函数求全班学生的总分和平均分。
【解答】
#include <iostream>
using namespace std;
classstudent
{
public:
voidscoretotalcount( double s )
{
score= s;
total= total + score;
count++;
}
staticdouble sum()
{
return total;
}
staticdouble average()
{
return total / count;
}
private:
double score;
staticdouble total;
staticdouble count;
};
doublestudent::total=0;
doublestudent::count=0;
intmain()
{
int i,n; double s;
cout << "请输入学生人数:";
cin >> n;
student stu;
for( i=1; i<=n; i++ )
{
cout << "请输入第"<< i << "个学生的分数:";
cin >> s;
stu.scoretotalcount( s );}
cout << "总分:"<< student::sum() << endl;
cout<< "平均分:"<< student::average() << endl;
}
4.定义一个表示点的结构类型Point和一个由直线方程y = ax + b确定的直线类Line。结构类型Point有两个成员x和y,分别表示点的横坐标和纵坐标。Line类有两个数据成员a和b,分别表示直线方程中的系数。Line类有一个成员函数print用于显示直线方程。友元函数setPoint(Line&l1,Line &l2)用于求两条直线的交点。在main函数中,建立两个直线对象,分别调用print函数显示两条直线的方程,并调用函数setPoint求这两条直线的交点。
【解答】
#include <iostream>
using namespace std;
structpoint
{
double x; double y;
};
classline
{
public:
line(double u, double v )
{
a=u; b=v;
}
voidprint()
{
cout<<"y="<<a<<"x+"<<b<<endl;
}
friend point setpoint(line &l1,line &l2);
private:
double a, b;
};
pointsetpoint( line &l1, line &l2 )
{
pointp;
p.x=(l2.b-l1.b )/( l1.a-l2.a );
p.y=(l1.a*l2.b-l2.a*l1.b)/(l1.a-l2.a );
returnp;
}
intmain()
{
point setp;
linel1(2,3), l2(4,5);
cout<<"直线l1:";
l1.print();
cout<<"直线l2:";
l2.print();
setp=setpoint( l1,l2 );
cout<<"直线l1和直线l2的交点:("<<setp.x<<","<<setp.y<<")"<<endl;
}
5.用类成员结构修改第4题的程序,使其实现相同的功能。定义Point类和Line类,表示点和线;定义setPoint类,包含两个Line类成员和一个表示直线交点的Point成员,并定义类中求直线交点的成员函数。编写每个类相应的成员函数和测试用的主函数。
【解答】
略。