1.?(选择题, 2 分)?
建立一个有成员对象的派生类对象时,各构造函数体的执行次序为? ? ? ?。
A. 派生类、成员对象类、基类
B. 基类、派生类、成员对象类
C. 基类、成员对象类、派生类
D. 成员对象类、基类、派生类
?
? C. ?基类、成员对象类、派生类
在建立一个有成员对象的派生类对象时,构造函数的执行顺序如下:
1. ?首先调用基类的构造函数,初始化基类成员变量。
2. ?然后调用成员对象类的构造函数,初始化成员对象类成员变量。
3. ?最后调用派生类的构造函数,初始化派生类成员变量和基类成员变量。
这个顺序确保了基类和成员对象的初始化在派生类构造函数之前完成,从而保证了派生类对象的完整性。
2.?(选择题, 2 分)?
下列关于虚函数的说明中,正确的是? ? ? ???。
A. 从虚基类继承的函数都是虚函数
B. 抽象类中的成员函数都是虚函数
C. 虚函数不得是静态成员函数
D. 只能通过指针或引用调用虚函数
?
? C. ?虚函数不得是静态成员函数
关于虚函数的说明,以下几点是正确的:
1. ?虚函数是用于实现多态的机制,它允许基类指针访问派生类中的成员函数。
2. ?虚函数必须是基类的非静态成员函数,其访问权限可以是protected或public。
3. ?虚函数不能是静态成员函数,因为静态成员函数在类外部无法访问,也就无法实现多态。
4. ?可以通过基类指针或引用调用虚函数,但也可以直接调用派生类的成员函数,不一定需要使用指针或引用。
选项A和B的描述是不准确的。从虚基类继承的函数不一定是虚函数,只有当派生类重新定义该函数时,它才成为虚函数。抽象类中的成员函数不一定是虚函数,但抽象类中必须包含至少一个纯虚函数。
?
3.?(选择题, 2 分)?
在C++中用来实现运行时多态性的是? ? ?。
A. 虚函数
B. 构造函数
C.?析构函数
D.?重载函数
?
? A. ?虚函数
在C++中,运行时多态性是通过虚函数实现的。虚函数允许基类指针或引用访问派生类的成员函数,从而在运行时根据实际对象类型调用相应的函数。这种多态性有助于提高代码的可扩展性和灵活性。
构造函数、析构函数和重载函数主要与对象的初始化和调用方式有关,它们不能直接实现多态性。构造函数和析构函数分别用于对象的初始化和清理,而重载函数是指具有相同函数名但参数列表不同的多个函数,它们在编译时确定调用哪个函数,与运行时多态性无关。
?
4.?(选择题, 2 分)
?
有如下程序:
#include <iostream>
using namespace std;
class A {
public:
? ? A( ) { cout << "A"; }
};
class B { public: B( ) { cout << "B"; } };
class C : public A {
? ? B b;
public:
? ? C( ) { cout << "C"; }
};
int main( ) {??C obj;? ?return 0; }
执行后的输出结果是????。
?
? 执行后的输出结果为:C
解析:
在这个程序中,我们定义了三个类A、B和C。类A和类B都是空构造函数,类C继承自类A,并在类C中定义了一个类B的成员变量。
当我们创建一个类C的对象obj时,首先调用类A的构造函数,输出"A",然后调用类B的构造函数,输出"B",最后调用类C的构造函数,输出"C"。因此,程序执行后的输出结果为"C"。
?
5.?(选择题, 2 分)?
下列关于运算符重载的叙述中,错误的是? ? ? ?。
A. 有的运算符只能作为成员函数重载
B. 有的运算符可以作为非成员函数重载
C. 所有的运算符都可以通过重载而被赋予新的含义
D. 不得为重载的运算符函数的参数设置默认值
?
? C. ? 所有的运算符都可以通过重载而被赋予新的含义
关于运算符重载,以下几点叙述是正确的:
1. ? 有的运算符只能作为成员函数重载,如一元运算符+、-、*、/、%等。这些运算符不能作为非成员函数重载。
2. ? 有的运算符可以作为非成员函数重载,如=、[]、()等。
3. ? 并非所有的运算符都可以通过重载而被赋予新的含义,例如,一些二元运算符(如+、-、*、/、%)不能被重载为非成员函数。
4. ? 为重载的运算符函数的参数设置默认值是允许的,但要注意,运算符函数的参数个数和顺序必须与原始运算符匹配。
选项C的描述是错误的。并非所有的运算符都可以通过重载而被赋予新的含义,有一些运算符不能被重载。
?
6.?(选择题, 2 分)
?
有如下程序:
??#include ?<iostream>
??using namespace std;
??class AA{
? ?int n;
??public:
? ?AA(int k):n(k){ }
? ?int get( ){ return n;}
? ?int get( )const{ return n+1;}
??};
??int main( )
??{
? ?AA a(5);
? ?const AA b(6);
? ?cout<<A.GET( )<<b.get( );
? ?return 0;
??}
? ??执行后的输出结果是??????。
?
?
A. 57
B. 55
C. 77
D. 75
?
? A.57
解析:
在这个程序中,我们定义了一个类AA,其中包含一个整型成员变量n,以及两个get()函数。第一个get()函数是无参的,第二个get()函数有一个常量参数。
在main()函数中,我们创建了一个AA类的对象a和一个常量AA类对象b。接着调用它们的get()函数,输出结果。
由于对象a是普通对象,调用的是非 ?const ?版本的 ?get() ?函数,返回 ?n ?的值,即 ?5。
对象b是常量对象,调用的是 ?const ?版本的 ?get() ?函数,返回 ?n+1 ?的值,即 ?7。
所以,程序执行后的输出结果是 ?57,选项A正确。
?
8.?(选择题, 2 分)
?
有如下类声明:
??class XA{
? ?int x;
??public:
? ?XA(int n){ x=n;}
??};
??class XB: public XA{
? ?int y;
??public:
? ?XB(int a,int b);
??};
? ??在构造函数XB的下列定义中,正确的是?????。
A. XB::XB(int a,int b): x(a), XB(b){ }
B. XB::XB(int a,int b): XA(a), XB(b){ }
C. XB::XB(int a,int b): x(a), y(b){ }
D. XB::XB(int a,int b): XA(a), y(b){ }
??
D. XB::XB(int a,int b): XA(a), y(b){ }
解析:
在C++中,当定义一个派生类的构造函数时,你必须首先初始化基类的部分。这是通过在派生类构造函数的初始化列表中调用基类的构造函数来完成的。在这个例子中,类XB继承自类XA。
选项A是错误的,因为它尝试直接初始化基类的私有成员x,并错误地尝试使用类名XB作为初始化器;
选项B也是错误的,因为它在初始化列表中错误地包含了对派生类自己的构造函数的调用;
选项C同样错误,因为它尝试直接初始化基类的私有成员x(对于基类私有成员的直接初始化是不允许的,应通过基类的构造函数完成);
选项D是正确的,它正确地首先调用基类XA的构造函数来初始化基类的成员变量x,然后初始化派生类自身的成员变量y。
?
9.?(选择题, 2 分)?
关于面向对象的程序设计方法,下列说法正确的是?????。
A. “多态性”指的是对象的状态会根据运行时要求自动变化
B. 在面向对象的程序设计中,结构化程序设计方法仍有着重要作用
C. 基类的私有成员在派生类的对象中不可访问,也不占内存空间
D. “封装性”指的是将不同类型的相关数据组合在一起,作为一个整体进行处理
?
B. 在面向对象的程序设计中,结构化程序设计方法仍有着重要作用
解析:
A. “多态性”指的是同一个行为具有多个不同表现形式或形态。它是通过抽象类和接口来实现的,使得相同的消息或方法调用可以产生不同的行为响应。因此,A项描述不准确。
B. 面向对象程序设计(OOP)是建立在结构化程序设计基础之上的,并且在其中一些原则,如模块化和分解,仍然是编程中非常重要的概念。因此,结构化程序设计方法在OOP中仍然重要。
C. 即使基类的私有成员在派生类的方法中不可直接访问,它们仍然存在于派生类对象的内存中,这为基类的私有成员在派生类中占据内存空间的说法是错误的。
D. “封装性”指的是将数据(属性)和行为(方法、函数)封装在一起,即创建类的概念。它并不是特指不同类型的数据组合,而是指任何形式的数据和行为的组合。因此,D项描述不准确。
因此,正确的选项是B。
?
10.?(选择题, 2 分)
?
有如下类声明:
class MyBASE{
? ?int k;
public:
??void set(int n){ k=n;}
??int get( )const{ return k; }
};
class MyDERIVED: protected MyBASE{
protected:
??int j;
public:
??void set(int m, int n){ MyBASE::set(m); j=n;}
??int get( )const{ return MyBASE::get( )+j; }
};
则类MyDERIVED中保护的数据成员和成员函数的个数是????。
?
?
A. 4
B. 3
C. 2
D. 1
?
B.3
解析:
在类MyDERIVED中,有一个明确声明为protected的数据成员,即int j。
然而,由于MyBASE的成员被继承为protected,在MyDERIVED中,基类MyBASE的所有public成员都将被当作protected成员。这包括set(int n)和get()这两个成员函数。但是,这里的关键点是基类MyBASE的成员int k没有被继承,因为它被声明为private,派生类不能直接访问基类的私有成员。
因此,MyDERIVED中的protected成员有:
1. 数据成员int j(明确声明为protected)
2. 成员函数void set(int m)(通过继承自MyBASE并且在MyDERIVED中以protected访问权限)
3. 成员函数int get() const(通过继承自MyBASE并且在MyDERIVED中以protected访问权限)
虽然基类MyBASE中的成员函数都以protected方式被继承到了MyDERIVED中,但是它们原本是public的,只是在MyDERIVED中的访问级别变成了protected。因此,它们算作MyDERIVED中的protected成员。
所以总共有3个protected的成员(一个数据成员和两个成员函数),选项B是正确的。
?
11.?(选择题, 2 分)
?
有如下程序:
#include <iostream>
using namespace std;
class BASE{
public:
? ?~BASE( ){ cout<<"BASE";}
};
class DERIVED: public BASE {
public:
??~DERIVED( ){ cout<<"DERIVED";}
};
int main( ){DERIVED x; return 0 ;}
执行后的输出结果是????。
?
?
A. DERIVEDBASE
B. DERIVED
C. BASEDERIVED
D. BASE
?
A. DERIVEDBASE
解析:
在C++中,当一个派生类对象被销毁时,首先会调用派生类的析构函数,然后再调用基类的析构函数。这确保了首先释放派生类分配的资源,然后是基类分配的资源。在这个程序中,当main函数结束时,局部对象x将被销毁,这会触发派生类DERIVED的析构函数的调用,打印"DERIVED"。在派生类的析构函数执行完毕后,接下来会调用基类BASE的析构函数,打印"BASE"。
因此,执行程序后的输出结果将会是"DERIVED"后跟"BASE",即"DERIVEDBASE"。所以正确答案是A。
?
12.?(选择题, 2 分)?
一个类可以同时继承多个类,称为多继承。下列关于多继承和虚基类的表述中,错误的是?????。
A.
多继承时有可能出现对基类成员访问的二义性问题
?
B. 每个派生类的构造函数都要为虚基类构造函数提供实参
C. 使用虚基类可以解决二义性问题并实现运行时的多态性
D. 建立最派生类对象时,虚基类的构造函数会首先被调用
?
C. 使用虚基类可以解决二义性问题并实现运行时的多态性
解析:
A. 在多继承中,如果两个或更多的基类有同名的成员,派生类如果不加以区分直接访问这些成员,的确会出现二义性问题。因此,A项是正确的。
B. 对于虚基类,无论有多少个派生类从这个虚基类派生,内存中只有一个虚基类的实例。每个派生类的构造函数需要调用虚基类的构造函数,提供实参以初始化虚基类的部分。因此,B项是正确的。
C. 虚基类确实可以解决由多个路径继承同一个基类导致的二义性问题,因为它保证在继承层次中只有一个基类的实例。但是虚基类本身并不实现运行时的多态性。多态性通常是通过虚函数(特别是通过基类指针或引用调用派生类的虚函数)实现的。因此,C项的描述是错误的。
D. 在构造最派生类的对象时,如果类有虚基类,那么虚基类的构造函数会首先被调用,以确保基类部分被正确初始化。这是为了防止基类的多次初始化和确保所有派生类都可以使用已经初始化的基类部分。因此,D项是正确的。
正确答案是C。
?
13.?(选择题, 2 分)?
在表达式 x+y*z中, + 是作为成员函数重载的运算符,* 是作为非成员函数重载的运算符。下列叙述中正确的是?????。
A. operator+有两个参数,operator*有两个参数
B. operator+有一个参数,operator*有一个参数
C. operator+有一个参数,operator*有两个参数
D. operator+有两个参数,operator*有一个参数
?
C. operator+有一个参数,operator*有两个参数
解析:
在C++中,如果一个运算符被重载为成员函数,它的第一个操作数是隐式传递的当前对象(即调用对象),而它的参数数量比操作数少一个。而如果一个运算符被重载为非成员函数,它通常需要与操作数数量相同的参数。
在表达式 `x+y*z` 中,`+` 被作为成员函数重载,那么 `x` 将会是调用对象,`y*z` 的结果将作为唯一的参数传递给 `operator+`。因此,`operator+` 有一个参数。
`*` 被作为非成员函数重载,表示它需要两个参数:一个是 `y`,另一个是 `z`。
因此,`operator+` 有一个参数,`operator*` 有两个参数。正确答案是C。
?
14.?(选择题, 2 分)?
对于通过公有继承定义的派生类,若其成员函数可以直接访问基类的某个成员,说明该基类成员的访问权限是? ? ? ??。
A. 私有
B. 公有或私有
C. 公有或保护
D. 保护或私有
?
C. 公有或保护
解析:
在C++中,通过公有继承定义的派生类可以直接访问基类中的公有成员和保护成员。
- 公有(public)成员既可以被派生类访问,也可以被基类以外的其他函数访问。
- 保护(protected)成员可以被派生类访问,但不能被基类以外的其他函数直接访问。
- 私有(private)成员不能被派生类直接访问,只能被基类自身的成员函数、友元函数和类本身访问。
因此,如果派生类的成员函数可以直接访问基类的某个成员,那么该基类成员的访问权限必须是公有或保护的。选项C是正确的。
?
15.?(选择题, 2 分)?
下列运算符函数中,肯定不属于类 Value 的成员函数的是? ? ? ?。
A. Value operator*(int);
B. Value operator+(Value);?
C. Value operator-(Value, Value);
D. Value operator/(Value);
?
C. Value operator-(Value, Value);
解析:
在C++中,运算符重载可以作为成员函数或非成员函数(全局函数)。如果运算符重载为成员函数,那么它的第一个操作数隐式地是调用它的对象,因此成员函数版本的运算符通常只需要一个参数,这个参数代表第二个操作数。
A. `Value operator*(int);` 表示 `Value` 对象乘以一个整数,可以是成员函数。
B. `Value operator+(Value);` 表示 `Value` 对象加上另一个 `Value` 对象,可以是成员函数。
C. `Value operator-(Value, Value);` 表示两个 `Value` 对象的减法,因为它有两个参数,所以它不能是成员函数(它必须是非成员函数)。
D. `Value operator/(Value);` 表示 `Value` 对象除以另一个 `Value` 对象,可以是成员函数。
基于这些信息,选项C是正确的答案,因为它有两个参数,所以不能是类 `Value` 的成员函数。
?
16.?(选择题, 2 分)?
在C++中,用于实现运行时多态性的是? ? ??。
A. 模板函数
B. 重载函数
C. 虚函数
D. 内联函数
答案 C
?
18.?(选择题, 2 分)
有以下类定义
class MyClass
{
public:
?? MyClass(){cout<<1;}
};
则执行语句MyClass a, b[2], *p[2];后,程序的输出结果是?????。
A. 111
B. 11111
C. 1111
D. 11
?
答案是 B. 11111
解析:
当执行语句 `MyClass a, b[2], *p[2];` 时,程序做了以下操作:
1. `MyClass a` 定义了一个 `MyClass` 的对象 `a`,会调用默认构造函数输出 `1`。
2. `b[2]` 定义了一个 `MyClass` 对象数组 `b`,大小为2,因此会调用两次默认构造函数,每次输出 `1`。
3. `*p[2]` 定义了一个指向 `MyClass` 的指针数组 `p`,大小为2,但并不创建 `MyClass` 的对象,所以不会调用构造函数,因此不产生输出。
所以总的输出结果是 `11111`。
?
19. (选择题, 2 分) 下列关于类和对象的叙述中,错误的是 。
A. 类是对某一类对象的抽象
B. 对象是类的具体实例?
C. 类和对象的关系是一种数据类型与变量的关系
D. 一个类只能有一个对象
?
D. 一个类只能有一个对象
解析:
A. 类是对某一类对象的抽象 —— 正确。在面向对象编程中,类是对具有相同属性和方法的一组对象的抽象。
B. 对象是类的具体实例 —— 正确。对象是根据类创建的,一个对象是类的一个实例,拥有类定义的属性和方法。
C. 类和对象的关系是一种数据类型与变量的关系 —— 正确。在编程中,类相当于数据类型,而对象相当于该类型的变量。
D. 一个类只能有一个对象 —— 错误。一个类可以有多个对象实例。事实上,通常一个类是为了创建多个具有类似属性和行为的对象而设计的。
因此,选项D是错误的叙述。
?
20.?(选择题, 2 分)
有如下类声明:
? class Foo {??int bar;??};
??则Foo类的成员bar是???。
A.?私有成员函数
B. 公有成员函数
C. 公有数据成员
D. 私有数据成员
?
D. 私有数据成员
解析:
在C++中,如果类成员前没有指定访问修饰符(如public, protected或private),那么默认的访问权限是private。在上面的类声明 `class Foo { int bar; };` 中,成员变量 `bar` 没有指定访问修饰符,因此它是私有的。
私有成员(Private members)只能被类的成员函数和友元函数访问,不能直接被外部访问。
因此,`bar` 是一个私有数据成员。
?
21.?(填空题, 5 分)
?
下列程序中,类DERIVE共有的继承了类BASE1和BASE2,请完善程序。
#include<iostream.h>
?class BASE1
{public:
int x;
BASE1(int a=0){x=a;}
void Print(){cout<<"x="<<x<<'\n';}
};
class BASE2
{protected:
int x;
public:
? BASE2(int a=0){x=a;}
void Print(){cout<<"x="<<x<<'\n';}
};
class DERIVE:public BASE1,?? ? ?(1)? ? ?
{ int z;
public:
DERIVE(int a,int b,int c)? :?? ? ?(2)? ???, BASE2(b)
????????{????z=c;}
????????int Area(){return BASE1::x*?? ? ?(3)? ? ?;}
void PrintC(){cout<<"z="<<z<<'\n';}
};
?
void main()
{
DERIVE d(10,20,50);
d.BASE1::Print(); //B
d.PrintC();
}
?
(1)public BASE2
(2)BASE1(a)
(3)BASE2::x
该程序定义了三个类:`BASE1`、`BASE2`和`DERIVE`。`BASE1`和`BASE2`都包含一个名为`x`的整型成员变量,但在`BASE1`中它是公有的(public),而在`BASE2`中它是受保护的(protected)。这两个基类还各自包含一个构造函数和一个打印`x`值的`Print`成员函数。
`DERIVE`类公有继承自`BASE1`和`BASE2`,意味着`BASE1`的公有成员和`BASE2`的受保护和公有成员都作为`DERIVE`的一部分。它还包含一个私有成员`z`和一个构造函数,该构造函数接受三个参数,分别用来初始化从`BASE1`和`BASE2`继承的`x`成员,以及`DERIVE`自己的`z`成员。
`DERIVE`的`Area`成员函数计算由`BASE1`的`x`和`BASE2`的`x`成员决定的“面积”,实际上是两个数值的乘积。由于`BASE1`和`BASE2`的`x`成员都是整型,它们的乘积也是整型。
`DERIVE`类还有一个`PrintC`成员函数,用于打印私有成员`z`的值。
最后,主函数`main`创建了一个`DERIVE`类的实例`d`,使用提供的值初始化`d`,然后调用`BASE1`的`Print`成员函数和`DERIVE`的`PrintC`成员函数来输出相应的值。
?
22.?(填空题, 4 分)?
若将一个二元运算符重载为类的成员函数,其形参个数应该是? ?【1】? ?个
答案 1
在C++中,当你重载一个二元运算符作为类的成员函数时,调用对象本身自动成为该运算符函数的第一个操作数(即左操作数),而你只需要为函数提供另一个操作数(即右操作数)。因此,你只需为该成员函数提供一个形式参数。这样,运算符函数就能够使用调用它的对象和这个参数作为操作数。
例如,如果你有一个类`Complex`用于表示复数,并且你想要重载加法运算符`+`,那么你会在类中定义一个成员函数,它只需要一个`Complex`对象作为参数:
```cpp
class Complex {
public:
? ? Complex operator+(const Complex& other) const {
? ? ? ? return Complex(re + other.re, im + other.im);
? ? }
private:
? ? double re, im;
};
```
在这里,`operator+`是成员函数,它只接受一个`Complex`类型的参数,称为`other`。当你使用加法运算符时,如`c1 + c2`,其中`c1`和`c2`都是`Complex`对象,`c1`会隐式地成为`operator+`的调用者(`this`指针所指向的对象),`c2`则作为`other`参数传递给函数。因此,成员函数`operator+`只需要一个额外的参数来代表第二个操作数。
?
23.?(填空题, 5 分)
?
建立一个student成绩类来实现如下功能:成员stu[10]用来存放学生考试成绩(假定不超过10人),Found函数查找考试成绩在80分以上的学生及其编号,count用来统计80分以上的学生人数。
#include<iostream.h>
?
class student{
?? int count;
?? int???①??;
?? float stu[10];
public:
?? student(float a[],int b){
?????? n=b;
?????? for(int i=0;i<n;i++)????????②????????;
?????? count=0;
?? }
?? void Found(){
?????? for(int i=0;i<n;i++)
?????????? if(stu[i]>=80){count++;?????③?????;}
?? }
?? void show(int m){
?????? cout<<"学生编号:"<<m+1<<"\t成绩:"<<stu[m]<<'\n';
?? }
?? void print(){
?????? cout<<"80以上学生数:"<<count<<endl;
?? }
};
?
填空答案:
① `n`
② `stu[i] = a[i];`
③ `cout << "学号:" << i + 1 << " 分数:" << stu[i] << endl;`
详解:
- ① `n`: 这个成员变量用于存储实际的学生数量,即数组`stu`中存放的成绩的数量。
- ② `stu[i] = a[i];`: 这部分是构造函数中的一个循环,用于初始化数组`stu`。构造函数接收一个浮点数数组`a`和一个整数`b`,其中`b`代表学生数量。这个循块应该将传入的数组`a`的值复制到类的成员数组`stu`中,因此我们需要在循环体中赋值:`stu[i] = a[i];`。
- ③ `cout << "学号:" << i + 1 << " 分数:" << stu[i] << endl;`: `Found`函数中的这个语句在找到分数在80分以上的学生时,打印出该学生的编号和成绩。由于数组索引从0开始,而学生编号通常从1开始,所以打印时对索引`i`进行了加1处理,以显示正确的学生编号。同时,显示该学生的成绩`stu[i]`。
?
24.?(填空题, 4 分)
已知类Ben中将二元运算符“/”重载为友元函数,若c1、c2是Ben的两个对象,当使用运算符函数进行显示调用时,与表达式c1/c2等价的表示为??【1】???。
?
【1】 operator/(c1, c2)
在C++中,运算符可以被重载为普通成员函数或者友元函数。重载为友元函数时,运算符的实现不属于类的成员方法,而是作为一个独立的函数,这意味着它可以在不是类成员的情况下访问类的私有成员。当二元运算符“/”被重载为一个友元函数时,它将需要两个参数:左侧操作数和右侧操作数。
如果`c1`和`c2`是`Ben`类的实例,并且“/”运算符被重载为友元函数,那么`c1 / c2`语句将隐式调用重载的运算符。与此等价的显式调用形式,即直接使用运算符函数调用的方法是`operator/(c1, c2)`。这是因为重载的运算符函数通常命名为`operatorX`,其中X是被重载的运算符。因此,对于“/”运算符的重载版本,函数名将是`operator/`。
这种显式调用方式直接用函数的形式调用重载的运算符,而不使用它的符号表示。这里的`operator/`是函数名,而`c1`和`c2`是传递给这个函数的实参。
?
25.?(填空题, 5 分)
?
请完善下列代码。
class Point? //定义点类
{ ? float x,y;
public:?
? ? ? ? Point(float a,float b)
? ? ? ?{ ? ? ?(1)? ? ???;
? ? ? ? ? ? ? ? cout<<"调用了Point类构造函数\n";
? ? ? ?}
? ? ? ~Point()
? ? ? {? ? ?cout<<"调用了Point类析构函数\n";}
? ? ? void Show(){ cout<< "x="<<x<<'\t'<<"y="<<y<<'\n';? }
};
class Circle//定义圆类
{? ? ? float r;
public:
? ? ? ?Circle(? ? ?(2)? ??)
? ? ? {? ? ? ?r=a;
? ? ? ? ? ? ? cout<<"调用了Circle类构造函数\n";
? ? ? }
? ? ? ~Circle(){ cout<<"调用了Circle类析构函数\n";}
? ? ? void Show()
? ? ? {? ? ? cout<<"r="<<r<<'\n'; }
};
class Column? ? //定义圆柱类
{ float h;
? ? Point p1;? ? //点类Point的对象为圆柱类的数据成员
Circle c1;? ? //圆类Circle的对象为圆柱类的数据成员
public:
? ? ?Column(float a,float b,float c,float d):?? ? ?(3)? ? ??
? ? ?{? ? ? ?h=d;? ? ? ? ?//类Column的数据成员初始化
? ? ?cout<<"调用了Column类构造函数\n";?
? ? ?}
? ? ?~Column(){ cout<<"调用了Column类析构函数\n";}
? ? ?void Show()
? ? ?{ ? ? ? ?p1.Show();
? ? ? ?c1.Show();
? ? ? ?cout<< "h="<<h<<'\n';?
? ? ?}
?};
void? main(void)
{? ? ?Column? ccp(1, 2, 3, 4);? ? ? //定义圆柱类对象
? ? ? ccp.Show();?
}
?
填空答案:
① `x=a; y=b;`
② `Point(float a,float b), float a`
③ `p1(a, b), c1(c), h(d)`
详解:
- ① 在 `Point` 类的构造函数中,我们需要初始化类中的 `x` 和 `y` 数据成员。因此,构造函数的初始化列表中应该包含 `x=a; y=b;`,这样就会把传入的参数 `a` 和 `b` 分别赋值给 `x` 和 `y`。
??
- ② 对于 `Circle` 类的构造函数,我们需要一个参数来初始化其半径 `r`。由于 `Circle` 类接收一个来自 `Point` 类的对象作为参数,并且需要一个浮点数来初始化半径,因此构造函数的参数列表应该是 `Point(float a,float b), float a`。这样,构造函数使用第二个参数 `a` 来初始化 `r`。
- ③ `Column` 类是一个组合类,包含了 `Point` 和 `Circle` 类的对象。`Column` 类的构造函数应该使用参数列表初始化其数据成员 `p1`,`c1` 和 `h`。因此,初始化列表应该是 `p1(a, b), c1(c), h(d)`,其中 `p1(a, b)` 是基于 `Point` 类的构造函数,`c1(c)` 是基于 `Circle` 类的构造函数,而 `h=d` 是直接初始化 `Column` 类自己的数据成员 `h`。这样,`Column` 类的构造函数使用传入的参数 `a`,`b`,`c` 和 `d` 来分别初始化其数据成员 `p1` 的 `x` 和 `y`,`c1` 的 `r`,以及自身的 `h`。
?
26.?(填空题, 4 分)?
用来派生新类的称为? ?【1】??,而派生出的新类称为它的子类或派生类。
【1】 基类
?
27.?(填空题, 4 分)
?
请按下面注释的提示,将类B的构造函数定义补充完整。?
class A
{
?????int a;
public:
???A(int aa=0) { a=aa; }
};
class B: public A {
?????int b;
? ? ?A c;
public:
//用aa初始化基类A,用aa+1初始化类对象成员c
B(int aa):??? 【1】??{ b=aa+2; }
};
?
【1】 A(aa), c(aa+1)
详解:
在类B的构造函数中,我们需要初始化派生自基类A的部分,以及类内嵌套的A类对象c。类B继承了类A,因此在构造类B的对象时,也需要调用基类A的构造函数。同时,类B还包含了一个A类型的成员对象c,它也需要被初始化。
- `A(aa)` 这部分是调用基类A的构造函数,用参数`aa`来初始化基类A的成员变量`a`。
- `c(aa+1)` 这部分是用`aa+1`来初始化B类内部的A类对象c。
构造函数的初始化列表`A(aa), c(aa+1)`确保了基类部分和类的成员对象c按照提供的参数正确初始化。在这之后,构造函数体中的`b=aa+2;`语句则是用来初始化B类自己的成员变量`b`。
?
28.?(填空题, 4 分)
?
下列程序的输出是3,请填充程序中的空缺,使该行形成一个运算符重载函数的定义。
#include<iostream>
using?namespace?std;
class?MyNumber{
int?n;
public:
MyNumber(int?k):n(k){}
_【1】_int()const{return?n,}
};
int?main(){
????MyNumber numl(3);
????cout<<int(numl);
????return?0;
}
【1】 operator
详解:
在C++中,您可以重载类型转换运算符,以便在类的实例上进行类型转换时执行特定的操作。在此情况下,我们希望重载转换为int
类型的运算符。运算符重载函数的书写格式通常为operator 类型()
,其中类型
是要转换成的类型。
?
29.?(填空题, 5 分)
?
下面程序在复数类定义多个构造函数,请完善程序。
#include<iostream.h>
class complex
{ ? float real,image;
public:
? ? complex();? ? ? ? ? ? ? ? ? ? ? ? //A,无参
? ? complex(float);? ? ? ? ? ? //B,一个参数
? ? complex(float? ,float? ) ;? ?//C,两个参数
? ? void display()
? ? {? ? cout<<"r="<<real<<" ,i="<<image<<endl;}?
};
? ? ? (1)? ? ? ???complex() //无参构造函数
{ real=0;? image=0;
cout<<"调用了不带参数的构造函数\n";
}
complex::complex(float r)? //一个参数
{ ? ? ?(2)? ? ? ??;? image=0;
cout<<"调用了有一个参数的构造函数\n";
}
complex::complex(?? ? ?(3)? ? ??) //两个参数
{ real=r;image=i;
cout<<"调用了有两个参数的构造函数\n";
}
void main()
{ complex A,? B(3.25),? C(4.0,2.0) ;
A.display();? B.display();? C.display();
}
?
【1】 complex::complex() //无参构造函数
【2】 real = r
【3】 float r, float i //两个参数
详解:
【1】处的complex::complex()是复数类complex的无参构造函数定义,用于初始化real和image两个成员变量为0,并输出一条调用无参构造函数的信息。
【2】处的real = r是类complex的单参数构造函数的一部分,它接收一个浮点数作为参数并将其赋值给成员变量real,而成员变量image在这个构造函数中被初始化为0。这个构造函数用于处理只有实部而没有虚部的复数的情况,并输出一条调用了单参数构造函数的信息。
【3】处的float r, float i是类complex的双参数构造函数的参数部分,它接收两个浮点数作为参数,分别代表复数的实部和虚部,并将它们分别赋值给成员变量real和image。这个构造函数用于完整地初始化一个复数对象,并输出一条调用了双参数构造函数的信息。
?
30.?(编程题, 10 分)
设计一个立方体类Box,它能计算并输出立方体的体积、表面积以及所有边的边长和。
?
为了设计一个立方体类`Box`,我们需要定义类的成员变量以及三个成员函数,分别用来计算体积、表面积和边长和。
类定义如下:
```cpp
class Box {
private:
? ? float length; // 立方体的边长
public:
? ? // 构造函数,初始化边长
? ? Box(float len) : length(len) {}
? ? // 计算并输出立方体的体积
? ? float volume() const {
? ? ? ? return length * length * length;
? ? }
? ? // 计算并输出立方体的表面积
? ? float surfaceArea() const {
? ? ? ? return 6 * length * length;
? ? }
? ? // 计算并输出所有边的边长和
? ? float edgeSum() const {
? ? ? ? return 12 * length;
? ? }
};
```
然后,我们可以在main函数中创建一个`Box`对象,并输出其体积、表面积和边长和:
```cpp
#include <iostream>
int main() {
? ? float edgeLength;
? ? std::cout << "Enter the length of the cube's edge: ";
? ? std::cin >> edgeLength;
? ? // 创建Box对象
? ? Box box(edgeLength);
? ? // 输出体积
? ? std::cout << "Volume of the cube: " << box.volume() << std::endl;
? ? // 输出表面积
? ? std::cout << "Surface area of the cube: " << box.surfaceArea() << std::endl;
? ? // 输出边长和
? ? std::cout << "Sum of the edges: " << box.edgeSum() << std::endl;
? ? return 0;
}
```
此代码段创建了一个立方体类`Box`,其中包含了计算体积、表面积和边长和的方法。用户可以输入边长,程序会计算出相应的体积、表面积和边长和,并将结果输出到终端。
?
31.?(编程题, 10 分)
说明三维坐标类,把三维坐标作为基类派生圆的类,新增数据成员半径,把圆作为基类派生圆柱体的类,新增数据成员高,要求有构造函数,输出成员的成员函数,在相关类中有求圆面积的成员函数,求体积的成员函数。并测试程序的正确性。
?
为了构建三维坐标类和基于它的派生类,我们将首先创建一个三维坐标基类`Point3D`,然后从这个基类派生出一个圆类`Circle`,并进一步从圆类派生出一个圆柱体类`Cylinder`。每个类都将包含构造函数和输出成员的函数,而`Circle`类将有一个计算面积的函数,`Cylinder`类将有一个计算体积的函数。
以下是这些类的定义和测试:
```cpp
#include <iostream>
#include <cmath>
const double PI = 3.14159265358979323846;
// 基类:三维坐标类
class Point3D {
protected:
? ? float x, y, z;
public:
? ? // 构造函数
? ? Point3D(float xVal, float yVal, float zVal) : x(xVal), y(yVal), z(zVal) {}
? ? // 输出成员
? ? void display() const {
? ? ? ? std::cout << "3D Point coordinates: (" << x << ", " << y << ", " << z << ")" << std::endl;
? ? }
};
// 派生类:圆类
class Circle : public Point3D {
protected:
? ? float radius;
public:
? ? // 构造函数
? ? Circle(float xVal, float yVal, float zVal, float r) : Point3D(xVal, yVal, zVal), radius(r) {}
? ? // 输出成员
? ? void display() const {
? ? ? ? Point3D::display();
? ? ? ? std::cout << "Circle radius: " << radius << std::endl;
? ? }
? ? // 计算面积
? ? float area() const {
? ? ? ? return PI * radius * radius;
? ? }
};
// 派生类:圆柱体类
class Cylinder : public Circle {
private:
? ? float height;
public:
? ? // 构造函数
? ? Cylinder(float xVal, float yVal, float zVal, float r, float h) : Circle(xVal, yVal, zVal, r), height(h) {}
? ? // 输出成员
? ? void display() const {
? ? ? ? Circle::display();
? ? ? ? std::cout << "Cylinder height: " << height << std::endl;
? ? }
? ? // 计算体积
? ? float volume() const {
? ? ? ? return area() * height; // 使用Circle::area()计算底面积
? ? }
};
// 测试程序
int main() {
? ? // 创建圆柱体对象
? ? Cylinder cyl(1.0, 2.0, 3.0, 4.0, 5.0);
? ? // 显示圆柱体的详细信息
? ? cyl.display();
? ? // 显示圆柱体的面积和体积
? ? std::cout << "Area of the base circle: " << cyl.area() << std::endl;
? ? std::cout << "Volume of the cylinder: " << cyl.volume() << std::endl;
? ? return 0;
}
```
这段代码定义了三个类,其中`Point3D`是三维坐标类,`Circle`是圆类,它继承了`Point3D`并增加了半径,`Cylinder`是圆柱体类,它继承了`Circle`并增加了高度。每个类都有构造函数用于初始化成员变量,以及display函数用于输出对象的信息。`Circle`类中有一个计算圆面积的成员函数`area`,`Cylinder`类中有一个计算体积的成员函数`volume`,它使用`Circle`类的`area`函数来计算基底圆的面积。最后,main函数创建了一个`Cylinder`对象并测试了所有功能,输出了圆柱的三维坐标、半径、高度、底面圆的面积和圆柱体的体积。
?