一.现有理数的加法运算。请按后列要求作答。
- 仔细、完整地阅读程序,对应题号填写注释。注释的内容包括两部分:1.本行的语句是什么;2.简述其功能或特点。例如,注释可以这样写:“友员函数;重载加法运算符(+)。”
#include<iostream.h> #include<math.h> #include<iomanip.h>
class Rational { private: int numerator,denominator; void simplify( ); void DtoF(double,int&,int&); public: Rational(int n,int d=1); Rational(double x=0); ~Rational(); void plus(const Rational&); Rational operator + (const Rational&); void showFraction( ); operator double( ); friend ostream &operator\<\< (ostream &output, Rational &t);重载 };
|
这题有些挠谭,只写了一点
- 对应题号把函数的定义补充完整。
int Rational::maxcommonFactor(int a,int b)
{ if(a%b==0) return b; return *(11)* ;-----------maxcommonFactor(b,a%b) ; } void Rational::simplify( ) { int temp=maxcommonFactor(abs(numerator),abs(denominator)); if(temp==1) return; numerator/=temp; denominator/=temp; return; } void Rational::DtoF(double x,int & n,int & d) { double s=fabs(x); d=1; while((s*d-int(s*d))>1e-15) d*=10; n=int(x*d); } Rational::Rational(int n,int d) { if(d==0) { cout\<\<"错误! 分母不能为 0。有理数将置为 0。"\<\<endl; numerator=0; denominator=1; } else { (12) ; ;-------------------正常赋值即可 } simplify(); }
Rational::Rational(double x)
{ DtoF(x,numerator,denominator); simplify(); } Rational::~Rational( ){ }
void Rational::plus(const Rational& addend)
{ numerator=addend.numerator\*denominator+addend.denominator\*numerator; denominator\*=addend.denominator; simplify(); } Rational Rational::operator + (const Rational& t) { Rational temp(0,1); temp.numerator=numerator\*t.denominator+denominator\*t.numerator; temp.denominator=denominator\*t.denominator; temp.simplify(); return temp; } void Rational::showFraction( )
{ if(numerator\<0 && denominator\<0 \|\| numerator\>=0 && denominator\>0) cout\<\<abs(numerator)\<\<"/"\<\<abs(denominator);
else cout\<\<"-"\<\<abs(numerator)\<\<"/"\<\<abs(denominator); } Rational::operator double()
{ return *(13)* ;----------------------------------double(numerator)/double(denominator) ; }
ostream &operator \<\<(ostream &output, Rational &t)
{ output\<\<t.numerator\<\<'/'\<\<t.denominator; return output; } void main()
{ Rational a; cout\<\<double(a); cout\<\<endl; Rational b(2,0); b.showFraction(); cout\<\<endl; Rational c(3,4); c.showFraction(); cout\<\<endl; Rational d(1.2); d.showFraction(); cout\<\<endl; a=b+c; cout\<\<double(a); cout\<\<endl; }
|
只是补充的话就比较简单了,你一定会
- 根据题目要求,按对应题号作答。
(14)写出上述程序的运行结果。
0 错误! 分母不能为0。有理数将置为0。 0/1 3/4 6/5 0.75
|
在上述程序中,使用成员函数重载加法运算符(+)。现假设要改用友员函数重载加法运算符(+),下面给出了函数体,请写出相应的函数原型(声明)和函数头。
函数原型 (15)
friend Rational operator + (const Rational &t1,const Rational &t2);
|
函数头 (16)
Rational operator + (const Rational &t1, const Rational &t2)
|
函数体
{ Rational temp(0,1); temp.numerator=t1.numerator\*t2.denominator+t1.denominator\*t2.numerator; temp.denominator=t1.denominator\*t2.denominator; temp.simplify(); return temp; }
|
在上述程序中,构造函数出现重载,我们按其定义的先后分别称为构造函数 1 和构造函数 2。注意到main 函数中依次定义了对象a,b,c,d。请你分别写出这四个对象的初始化各自调用的是哪一个构造函数。
对象 a 初始化: 构造函数2
;
对象 b 初始化: 构造函数1
;
对象 c 初始化: 构造函数
1;
对象 d 初始化: 构造函数2
;
在上述程序中,请你补充一个复制构造函数的定义,要求用内联函数实现。
(18)
Rational(const Rational& r) { numerator=r.numerator; denominator=r.denominator; }
|
复制构造函数和重载赋值运算符函数虽然都是实现数据成员的复制,但执行时机不同。复制构造函数通常用于初始化对象
和传递对象参数,当函数返回类类型时,也要通过复制构造函数建立临时对象;重载赋值运算符函数用于程序运行时修改对象的数据 。
·假设在上述程序的基础上,于main 函数末尾处添加一行:
for(int i=0;i<=1;i++) c.plus(c+d); cout<<double(c)<< ','<< double(d)<<endl;
|
写出这段语句的运行结果。
(20)6.6,1.2
二、给出一些类的定义,按要求作答。
- (每小题 3 分,共 18 分)
#include\<iostream.h\> class A { private: double x; public: A(double px=1):x(px) { } double getx( ) const { return x; } void show( ) { cout\<\<"x="\<\<x\<\<endl; } } ;
class B: private A { private: double x; public : B(double px=2): x(px){ } void show( ) { cout\<\<getx( )\<\<endl; } } ; void main( ) { A a; a.show( ); B b(3); b.show( ); }
|
·执行上述程序,运行结果为:
(21)
若把类B 构造函数定义改为 B(double px=2):A(px){ }
,则程序运行结果为:
(22)
改写上述程序中的类B 构造函数定义 B(double px=2): x(px){ }
。要求不使用“初始化式”,但函数的功能不变,且内联函数的形式也不变。按要求,类 B 构造函数定义可以改写成:
(23)
有时需要复制 A 类对象的数据去创建 B 类对象,请用内联函数的形式写出类 B 的重载构造函数:
(24)
B(const A& a) { x=a.getx( ); }
|
假设在上述main 函数的末尾添加一句:cout<<b.getx( )<<endl;
因getx( )
私有,不可访问。请你在类 B 的定义中作一声明,保持getx( )仍为公有,使添加的语句可以运行。该声明为:
(25)
Public继承: 基类的 public 成员在派生类中仍然是 public。 基类的 protected 成员在派生类中仍然是 protected。 基类的 private 成员在派生类中不可访问。 Protected继承: 基类的 public 成员在派生类中变为 protected。 基类的 protected 成员在派生类中仍然是 protected。 基类的 private 成员在派生类中不可访问。 Private继承: 基类的 public 成员在派生类中变为 private。 基类的 protected 成员在派生类中变为 private。 基类的 private 成员在派生类中不可访问。 使用 using 声明可以将基类的成员引入派生类的作用域中,从而改变它们在派生类中的访问权限。对于 private 继承特别有用,因为它可以将本来在 private 继承中变为 private 的成员重新提升到 public 或 protected。 在C++中,只有基类中的public和protected成员才能通过using声明在派生类中引入,并使其在派生类的作用域中变为public或protected,从而可以在类外访问。基类中的private成员是不能通过这种方式在派生类中引入和访问的。
|
在类 B 公有段增加一个内联函数fetch的定义,其功能是返回 B 类对象数据 x 的平方值。
(26)
double fetch() { return x*x; }
|
- (每小题 3 分,共 18 分)
下列程序中,类 $B1,B2$ 虚继承类 A,类 C 多继承 $B1,B2$。按题目要求作答。注意 A 为虚基类,建立间接派生类对象时,只有一个 a 对象的数据成员版本。
#include<iostream.h> class A { public: double x,y; A(double px=1,double py=1):x(px),y(py){ } virtual ~A( ){ } void show( ) { cout\<\<"[A]=>"\<\<x\<\<","\<\<y\<\<endl; } } ; class B1: virtual public A { public : B1(double px=2, double py=2):A(px,py){ } void show() { cout\<\<"\[B1\]=\>"\<\<x\*y\<\<endl; } } ; class B2: virtual public A { public: double z; B2(double px=3, double py=3, double pz=3):A(px,py),z(pz){} void show() { cout\<\<"\[B2\]=\>"\<\<0.5\*(x+y)\*z\<\<endl; } } ; class C: public B1, public B2 { public: double h; C(double px=4,double py=4,double pz=4,double ph=4):B2(px,py,pz),h(ph){} void show() { cout\<\<"\[C \]=\>"\<\<x\<\<","\<\<y\<\<"/"\<\<x\*y\*h\<\<"/"\<\<0.5\*(x+y)\*z\*h\<\<endl; } } ; void main() { A a; B1 b1; B2 b2; C c; A* p=&a; p-\>show( ); p=&b1; p-\>show( ); p=&b2; p-\>show( ); p=&c; p-\>show( ); }
|
写出上述程序的运行结果。
(27)
[A ]=>1,1 [A ]=>2,2 [A ]=>3,3 [A ]=>1,1
|
此处为虚拟继承,前三步一致,最后一步因为虚拟继承的特性,b1,b2会共用一份a,从层次结构上,a脱离于c的构造函数而提前构造,b1,b1在层次结构上和c连接,因此会跟随c的构造函数提前构造。 当不使用虚拟继承时,就会恢复为全部依靠c的构造函数而一步步提前构造的情况。 此外,由于未使用virtual修饰show,所以所有的a的指针都会指向该对象中的a的show。
|
在类A 的show 函数之前加上关键字 virtual,再写出上述程序的运行结果。
(28)
[A ]=>1,1 [B1]=>4 [B2]=>9 [C ]=>1,1/4/16
|
在(28)题基础上,于原 main 函数的末尾添加 ((B2)c).show( ); 结果将多显示一行:
(29)
子类到父类的强制类型转换就像大瓶子的水装到小瓶子中,必然会损失一些数据,这些数据就是子类不同于父类的一部分
|
·把类A 的show 函数改写成纯虚函数。
(30)
若类 A 的show 函数改写成纯虚函数,原来的 main 函数不能正常运行,为什么?请简单说明理由。
类A的show函数改写成纯虚函数,具有纯虚函数的类A成为抽象类,而抽象类是不能建立对象的。原来的main函数中,有语句“A a;” 即对类A建立对象a,因此不能正常运行。
|
解释下抽象类和纯虚函数。 1.其子类必须重写纯虚函数,否则会出现类似于指针悬挂的情况。 2.虚拟继承或是其他任何继承都不会影响抽象类的使用 3.任何方式的实例化抽象类都是不允许的,除非在子类的构造函数中以构造的形式,就像是子类的重写接口未对上,导致纯虚函数的指针悬挂了一样
|
(31)
类 A 的show 函数改写成纯虚函数后,请你对原来的 main 函数作简单的删改,使其可以输出派生类的数据。
(32)
B1 b1; B2 b2; C c; A* p=&b1; p->show(); p=&b2; p->show(); p=&c; p->show();
|
三、给出一些关于使用模板的程序段,按要求作答。
- 下列程序用函数模板实现两个数据的交换,请把有关的语句填充完整。
#include<iostream> template <(33)>--------typename T
void swap(*(34)* ) -------T&a,T&b {*(35)* } ------------------T c=a;a=b;b=a; void main() { int j=1,k=3; cout\<\<"int 数据类型:\n"\<\<j\<\<","\<\<k\<\<"=\>"; swap(j,k); cout\<\<j\<\<","\<\<k\<\<endl; double x=1.23,y=9.87;
cout\<\<"double 数据类型: \n"\<\<x\<\<","\<\<y\<\<"=\>"; swap(x,y); cout\<\<x\<\<","\<\<y\<\<endl;
char p='A',q='B'; cout\<\<"char 数据类型:\n"\<\<p\<\<","\<\<q\<\<"=\>"; swap(p,q); cout\<\<p\<\<","\<\<q\<\<endl ;
}
|
- 下列程序使用了向量 vector 和算法 sort 实现数组的排序,请把有关的语句填充完整。
#include<iostream> #include<vector> #include<algorithm> using *(36)* ;---------namespace std; const int size=10; void display(vector\<int\>V,int n) { int i; for(i=0;i\<size;i++) cout\<\<*(37)* \<\<" ";---------V[i]; cout\<\<endl; } bool down(int x,int y) { return *(38)* ;-------------------x>y } void main( ) { int a\[size\]={10,3,17,6,15,8,13,34,25,2}; vector\<int\>V(a,a+size); cout\<\<"输出原始数组: \n"; display(V,size); sort(V.begin( ),V.end( )); cout\<\<"输出升序排列后的数组: \n" ; display(V,size); sort(V.begin( ),V.end( ),down); cout\<\<"输出降序排列后的数组: \n" ; display(V,size); }
|
四、给出一个输入输出流操作的程序段,请把有关的语句填充完整。
#include <iostream.h\> #include <fstream.h\> #include <stdlib.h\> void main( ) { ofstream outstuf ;
outstuf.open("e:\\newfile.dat",*(39)* ); ------------ios::out if(!outstuf) { cerr\<\<"error!"\<\<endl;abort( ); }
outstuf *(40)* ;-------------.close()
}
|
总结
本试卷考察:模板,文件,继承(虚拟继承)