一、 填空题
- 类定义中关键字private、public和protected以后的成员的访问权限分别是 私有、公有 和 保护。如果没有使用关键字,则所有成员默认定义为 private 权限。具有 public 访问权限的数据成员才能被不属于该类的函数所直接访问。
- 定义成员函数时,运算符“∷”是 作用域 运算符,“MyClass∷”用于表明其后的成员函数是在“MyClass类”中说明的。
- 在程序运行时,通过为对象分配内存来创建对象。在创建对象时,使用类作为样板,故称对象为类的实例。
- 假定Dc是一个类,则执行“Dc a[10],b(2)”语句时,系统自动调用该类构造函数的次数为11。
- 对于任意一个类,析构函数的个数最多为1个。
- delete运算符通常用于实现释放该类对象中指针成员所指向的动态存储空间的任务。
- C++程序的内存格局通常分为4个区: 数据区、代码区、栈区和堆区。
- 数据定义为全局变量,破坏了数据的 封装性; 较好的解决办法是将所要共享的数据定义为类的 静态成员。
- 静态数据成员和静态成员函数可由 任意访问权限许可的函数访问。
- 友元函数 和 友元类 统称为友元。
- 友元的正确使用能提高程序的效率,但破坏了类的封装性和数据的隐蔽性。
- 若需要把一个类A定义为一个类B的友元类,则应在类B的定义中加入一条语句: friend class A;。
二、 选择题(至少选一个,可以多选)
- 以下不属于类访问权限的是( B )。
A. public
B. static
C. protected
D. private - 有关类的说法不正确的是( BC )。
A. 类是一种用户自定义的数据类型
B. 只有类的成员函数才能访问类的私有数据成员
C. 在类中,如不做权限说明,所有的数据成员都是公有的
D. 在类中,如不做权限说明,所有的数据成员都是私有的 - 在类定义的外部,可以被任意函数访问的成员有( C )。
A. 所有类成员
B. private或protected的类成员
C. public的类成员
D. public或private的类成员 - 关于类和对象的说法( C )是错误的。
A. 对象是类的一个实例
B. 任何一个对象只能属于一个具体的类
C. 一个类只能有一个对象
D. 类与对象的关系和数据类型与变量的关系相似 - 设MClass是一个类,dd是它的一个对象,pp是指向dd的指针,cc是dd的引用,则对成员的访问,对象dd可以通过( B )进行,指针pp可以通过( D )进行,引用cc可以通过( B )进行。
A. ∷
B. .
C. &
D. -> - 关于成员函数的说法中不正确的是( C )。
A. 成员函数可以无返回值
B. 成员函数可以重载
C. 成员函数一定是内联函数
D. 成员函数可以设定参数的默认值 - 下面对构造函数的不正确描述是( B )。
A. 系统可以提供默认的构造函数
B. 构造函数可以有参数,所以也可以有返回值
C. 构造函数可以重载
D. 构造函数可以设置默认参数 - 假定A是一个类,那么执行语句“A a,b(3),*p; ”调用了( B ) 次构造函数。
A. 1
B. 2
C. 3
D. 4 - 下面对析构函数的正确描述是( AC )。
A. 系统可以提供默认的析构函数
B. 析构函数必须由用户定义
C. 析构函数没有参数
D. 析构函数可以设置默认参数 - 类的析构函数是( D )时被调用的。
A. 类创建
B. 创建对象
C. 引用对象
D. 释放对象 - 创建一个类的对象时,系统自动调用( B ); 撤销对象时,系统自动调用( C )。
A. 成员函数
B. 构造函数
C. 析构函数
D. 复制构造函数 - 通常拷贝构造函数的参数是( C )。
A. 某个对象名
B. 某个对象的成员名
C. 某个对象的引用名
D. 某个对象的指针名 - 关于this指针的说法正确的是( B )。
A. this指针必须显式说明
B. 当创建一个对象后,this指针就指向该对象
C. 成员函数拥有this指针
D. 静态成员函数拥有this指针。 - 下列关于子对象的描述中,( B )是错误的。
A. 子对象是类的一种数据成员,它是另一个类的对象
B. 子对象可以是自身类的对象
C. 对子对象的初始化要包含在该类的构造函数中
D. 一个类中能含有多个子对象作其成员 - 对new运算符的下列描述中,( B )是错误的。
A. 它可以动态创建对象和对象数组
B. 用它创建对象数组时必须指定初始值
C. 用它创建对象时要调用构造函数
D. 用它创建的对象数组可以使用运算符delete来一次释放 - 对delete运算符的下列描述中,( D )是错误的。
A. 用它可以释放用new运算符创建的对象和对象数组
B. 用它释放一个对象时,它作用于一个new所返回的指针
C. 用它释放一个对象数组时,它作用的指针名前须加下标运算符[ ]
D. 用它可一次释放用new运算符创建的多个对象 - 关于静态数据成员,下面叙述不正确的是( C )。
A. 使用静态数据成员,实际上是为了消除全局变量
B. 可以使用“对象名.静态成员”或者“类名∷静态成员”来访问静态数据成员
C. 静态数据成员只能在静态成员函数中引用
D. 所有对象的静态数据成员占用同一内存单元 - 对静态数据成员的不正确描述是( CD )。
A. 静态成员不属于对象,是类的共享成员
B. 静态数据成员要在类外定义和初始化
C. 调用静态成员函数时要通过类或对象激活,所以静态成员函数拥有this指针
D. 只有静态成员函数可以操作静态数据成员 - 下面的选项中,静态成员函数不能直接访问的是( D )。
A. 静态数据成员
B. 静态成员函数
C. 类以外的函数和数据
D. 非静态数据成员 - 在类的定义中,引入友元的原因是( A )。
A. 提高效率
B. 深化使用类的封装性
C. 提高程序的可读性
D. 提高数据的隐蔽性 - 友元类的声明方法是( A )。
A. friend class<类名>;
B. youyuan class<类名>;
C. class friend<类名>;
D. friends class<类名>; - 下面对友元的错误描述是( D )。
A. 关键字friend用于声明友元
B. 一个类中的成员函数可以是另一个类的友元
C. 友元函数访问对象的成员不受访问特性影响
D. 友元函数通过this指针访问对象成员 - 下面选项中,( C )不是类的成员函数。
A. 构造函数
B. 析构函数
C. 友元函数
D. 拷贝构造函数
三、 简答题
- 类与对象有什么关系?
类是一种用户自己定义的数据类型,和其他数据类型不同的是,组成这种类型的不仅可以有数据,而且可以有对数据进行操作的函数。程序员可以使用这个新类型在程序中声明新的变量,具有类类型的变量称为对象。创建对象时,类被用做样板,对象称为类的实例。
- 类定义的一般形式是什么?其成员有哪几种访问权限?
定义类一般形式为:
class类名{
public:<公有数据和函数>
protected:<保护数据和函数>
private:<私有数据和函数>
};
- 1
- 2
- 3
- 4
- 5
访问权限共有3种:
公有(public)、保护(protected)和私有(private)。
- 1
- 类的实例化是指创建类的对象还是定义类?
指创建类的对象。
- 什么是this指针?它的主要作用是什么?
this指针是C++语言为成员函数提供的一个隐含对象指针,它不能被显式声明。this指针是一个局部量,局部于某个对象。不同的对象调用同一个成员函数时,编译器根据this指针来确定应该引用哪一个对象的数据成员。
- 什么叫做拷贝构造函数?拷贝构造函数何时被调用?
拷贝构造函数是一种特殊的构造函数,它的作用是用一个已经存在的对象去初始化另一个对象。为了保证所引用的对象不被修改,通常把引用参数声明为const参数。
在以下3种情况下,拷贝构造函数都会被自动调用:
◆当用类的一个对象去初始化该类的另一个对象时;
◆当函数的形参是类的对象,进行形参和实参结合时;
◆当函数的返回值是类的对象,函数执行完成返回调用者时。
四、 程序分析题(写出程序的输出结果,并分析结果)
(1)
#include<iostream>
using namespace std;
class Test
{
private:
int num;
public:
Test();
Test(int n);
};
Test::Test()
{
cout<<"Init defa"<<endl;\
num=0;
}
Test::Test(int n)
{
cout<<"Init"<<""<<n<<endl;
num=n;
}
int main()
{
Test x[2];
Test y(15);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
输出结果:
结果分析:
1.程序声明了2个对象x和y,类中有2个构造函数。
2.程序首先执行语句Test x[2];
,创建对象x,调用默认构造函数。由于对象x是对象数组,每个数组元素被创建时都要调用构造函数,所以默认构造函数被调用了2次,输出第1、2行结果。程序接着执行语句Test y(15);
,创建对象y,调用带一个参数的构造函数,输出第3行结果。
(2)
#include<iostream>
using namespace std;
class Xx
{
private:
int num;
public:
Xx(int x){num=x;}
~Xx(){cout<<"dst"<<num<<endl;}
};
int main()
{
Xx w(5);
cout<<"Exit main"<<endl;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
输出结果:
结果分析:
- 程序声明了一个对象w。 首先执行语句
Xx w(5);
,创建对象w,调用构造函数,num得到初值5。程序接着执行语句cout<<"Exit main"<<endl;>
,输出第1行结果。当程序结束时,释放对象w,析构函数被调用,输出第2行结果。
(3)将例3.10中的Whole类如下修改,其他部分不变,写出输出结果。
class whole
{
public:
whole(int i); //whole的有参构造函数
whokle(){}; //whole的无参构造函数
~whole(); //whole的析构函数
private:
Part p1; //子对象1
Part p2; //子对象2
Part p3; //子对象3
};
whole::whole(int i):p1(i),p2()
{
cout<<"constructor of whole"<<endl;
}
whole::~whole()
{
cout<<"destructor of whole "<<endl;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
修改后代码:
#include<iostream>
using namespace std;
class Part
{
public:
Part();
Part(int x);
~Part();
private:
int val;
};
Part::Part()
{
val=0;
cout<<"default constructor of part"<<endl;
}
Part::Part(int x)
{
val=x;
cout<<"constructorof part "<<","<<val<<endl;
}
Part::~Part()
{
cout<<"destructor of part"<<","<<val<<endl;
}
class whole
{
public:
whole(int i); //whole的有参构造函数
whokle(){}; //whole的无参构造函数
~whole(); //whole的析构函数
private:
Part p1; //子对象1
Part p2; //子对象2
Part p3; //子对象3
};
whole::whole(int i):p1(i),p2()
{
cout<<"constructor of whole"<<endl;
}
whole::~whole()
{
cout<<"destructor of whole "<<endl;
}
int main()
{
whole w(3);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
输出结果:
结果分析:
程序中的whole类中出现了类Part的三个对象p1 p2 p3,作为该类的数据成员,且被称为子对象。当建立whole类的对象w时,子对象p1p2p3被建立,相应的构造函数被执行,即类Part的默认构造函数。初始化p3的时候,由于whole 类构造函数的成员初始化列表中没有子对象p3进行初始化的对象,所以执行类Part的默认构造函数。当所有的子对象被构造完成之后,对象w的构造函数才被执行,即为第四行的结构,后面执行相应的析构函数。
(4)
#include<iostream>
using namespace std;
class book
{
public:
book(int w);
static int sumnum;
private:
int num;
};
book::book(int w)
{
num =w;
sumnum -=w;
}
int book::sumnum=120; //语句1
int main()
{
book b1(20); //语句2
book b2(70); //语句3
cout<<book::sumnum<<endl;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
输出结果:
结果分析:
程序中语句1对静态成员sumnum进行初始化,sumnum得到初值120。执行语句2时,调用构造函数,sumnum变为100。接着语句3,再调用构造函数,sumnum变为30。
五、 程序设计题
(1) 声明一个Circle类,有数据成员radius(半径)、成员函数area(),计算圆的面积,构造一个Circle的对象进行测试
程序设计:
#include<iostream>
using namespace std;
class Circle
{
public:
Circle(float r){radius = r;}
~Circle(){}
float area(){return 3.14*radius*radius;}
private:
float radius;
};
int main()
{
float r;
cout<<"请输入半径:";
cin>>r;
Circle p(r);
cout<<"半径为"<<r<<"的圆的面积为:"<<p.area()<<endl;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
输出结果:
(2)重新编写程序分析题(4)的程序,设计一个静态成员函数,用来输出程序分析题(4)中静态数据成员的值。
#include<iostream>
using namespace std;
class book
{
public:
book(int w);
static int sumnum;
static int getsum(){return sumnum;}
private:
int num;
};
book::book(int w)
{
num=w;
sumnum-=w;
}
int book::sumnum=120;
int main()
{
book b1(20);
book b2(70);
cout<<book::getsum()<<endl;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
输出结果: