习题13答案
一、简答题
1.什么是运算符重载?实现运算符重载有几种方法?如何实现?
答案:C++提供的运算符重载机制能够实现将已有运算符应用到新的数据类型变量上,赋予运算符新的含义。C++对运算符重载有一些限制,见13.2.1节。
有两种方法可以实现运算符重载,它们是:类的成员函数方式和有友元函数方式。
定义友元的目的是在友元函数中直接访问类的私有成员。实际上,可以通过类的公有函数接口访问类的私有成员,所以实现运算符重载,可以使用非成员、非友元实现运算符的重载。但是这种实现方法增加了访问私有数据成员的公有函数的调用时间,不值得提倡。见13.2.2节。
2.如何实现本类对象与其它类对象之间的相互类型转换?
答案:可以使用“类型转换函数”将本类对象转换成其他类对象。而“类型转换函数”本质上就是运算符的重载。另外,可以使用“构造函数”将其他类对象转换成本类对象。
3.什么是虚函数?什么是纯虚函数?它们的作用是什么?
答案:
多态性是面向对象程序设计的重要特性,它与前面讲的封装性和继承性构成面向对象程序设计的三大特性。这三大特性是互相关联的,封装性是基础,继承性是关键,而多态性是补充。
多态分为静态多态和动态多态。函数重载和运算符重载属于静态多态。动态多态是运行时的多态,如某些函数的调用关系在运行阶段才能确定。为了实现函数调用关系的动态多态,可以将函数定义成虚函数。将一个成员函数定义成虚函数的方法是,在函数定义的返回值类型前加virtual。
在抽象类中,有时无法实现某一功能(即无法决定某一函数的具体实现),只能将函数定义成纯虚函数。
虚函数具有函数实现的函数体,而纯虚函数没有函数体,即没有函数实现。对纯虚函数,只能在其派生类中实现该函数的功能。
4.试比较虚函数与虚基类的概念及作用。
答案:虚函数用于实现动态多态。而虚基类用于实现在多重继承情况下,基类数据成员在派生类中保留一个副本,见12.6节。
二、选择题
答案:
1. C
2. D
3. A
4. D
5. B
6. C
7. D
8. C
三、运行结果、完善程序
1.
运行结果:
n=4
n=3
2.
答案:
先看虚线框中的程序,运行结果为:D::show( ) called. 8
若将A行的virtual去掉,则结果为:B::show( ) called. 5
对本题,若将虚线框中的fun( )和main( )函数同时修改成右侧实线框中的对应函数,则若A 行有virtural时,结果为:D::show( ) called. 8 ;
若A行无virtual时,结果为:B::show( ) called. 5 。
3.
运行结果为:
The B version B
The D1 info: 4 version 1
The D2 info: 100 version B
The D3 info: -25 version 3
去掉A行的virtual,则运行结果为:
The B version B
The B version 1
The B version B
The B version 3
4.
答案:
(1)operator char *( )
(2)return s;
(3)str = num;
四、编程题
1.
答案:
// 实现1,赋值运算符重(=和+=)载函数的返回值为对象的引用。
// 缺点:不可实现对象的连续赋值,只能c1= c2
#include
class Complex
{
float Real, Image;
public:
Complex(float r=0,float i=0)
{
Real=r;Image=i;
}
void show( )
cout<<"("< } void operator=(Complex &); //用成员实现,注意:=不能用友元实现void operator+=(Complex &); //用成员实现,+=可以用友元实现 friend Complex operator+(Complex &,Complex &); //用友元实现 friend Complex operator-(Complex &,Complex &); //用友元实现 }; void Complex:: operator=(Complex &c) //返回值void { Real=c.Real; Image=c.Image; } void Complex:: operator+=(Complex &c) //返回值void { Real=Real+c.Real; Image=Image+c.Image; } Complex operator+(Complex &c1, Complex &c2) { Complex t; t.Real=c2.Real+c1.Real; t.Image=c2.Image+c1.Image; return t; } Complex operator-(Complex &c1, Complex &c2) { Complex t; t.Real=c1.Real-c2.Real; t.Image=c1.Image-c2.Image; return t; } void main( ) { Complex c1(1,2),c2(3,4),c3; c3=c1; c3.show( ); c3=c1+c2; c3.show( ); c3+=c2; c3.show( ); c3=c1-c2; c3.show( ); } // 实现2,赋值运算符重(=和+=)载函数的返回值为对象的引用。 // 优点:可实现对象的连续赋值,如c1=c2=c3 #include class Complex { float Real, Image; public: Complex(float r=0,float i=0) { Real=r;Image=i; } void show( ) { cout<<"("< } Complex & operator=(Complex &); //用成员实现,注意:=不能用友元实现Complex & operator+=(Complex &); //用成员实现,+=可以用友元实现 friend Complex operator+(Complex &,Complex &); //用友元实现 friend Complex operator-(Complex &,Complex &); //用友元实现 }; Complex & Complex:: operator=(Complex &c) //返回值为对象的引用 { Real=c.Real; Image=c.Image; return *this; } Complex & Complex:: operator+=(Complex &c) //返回值为对象的引用 { Real=Real+c.Real; Image=Image+c.Image; return *this; } Complex operator+(Complex &c1, Complex &c2) { Complex t; t.Real=c2.Real+c1.Real; t.Image=c2.Image+c1.Image; return t; } Complex operator-(Complex &c1, Complex &c2) { Complex t; t.Real=c1.Real-c2.Real; t.Image=c1.Image-c2.Image; return t; } void main( ) { Complex c1(1,2),c2(3,4),c3; c3=c2=c1; c3.show( ); c3=c1+c2; c3.show( ); c3+=c2; c3.show( ); c3=c1-c2; c3.show( ); } 2. 答案: #include #include class Fraction { int m, n; // m 是分子,n 是分母 public: Fraction(int im=0,int in=1) { int t=gcd(im,in); m=im/t; n=in/t; if(m*n>0) // 若分子和分母同号 { m=abs(m); n=abs(n); } else // 若分子和分母异号 { m=-abs(m); n=abs(n); }; } int gcd(int x,int y); Fraction & operator= ( Fraction b ) { m=b.m; n=b.n; return *this; } Fraction operator+ ( Fraction b ) { return Fraction(m*b.n+n*b.m,n*b.n); } Fraction operator- ( Fraction b ) { return Fraction(m*b.n-n*b.m,n*b.n); } friend Fraction operator* ( Fraction a, Fraction b ); friend Fraction operator/ ( Fraction a, Fraction b ); void Show() { cout< }; int Fraction::gcd(int x,int y ) //返回的最大公约数是正数{ int r; if(x<0) x= -x; if(y<0) y= -y; while( r=x%y ) { x=y; y=r; } return y; } Fraction operator* ( Fraction a, Fraction b ) { return Fraction(a.m*b.m, a.n*b.n); } Fraction operator/ ( Fraction a, Fraction b ) { return Fraction(a.m*b.n, a.n*b.m); } void main( ) { Fraction a(1,3),b(3,-12),c; cout<<"a="; a.Show( ); cout<<"b="; b.Show( ); c=a+b; cout<<"a+b="; c.Show(); c=a-b; cout<<"a-b="; c.Show(); c=a*b; cout<<"a*b="; c.Show(); c=a/b; cout<<"a/b="; c.Show(); } 3. 答案: #include class Point { float x,y; public: Point(float a=0,float b=0) { x=a;y=b; } void show( ) { cout<<"x="< Point & operator++( ); //用成员函数实现前置,返回引用 Point operator++(int); //用成员函数实现后置,返回对象 friend Point & operator--(Point &); //用友元函数实现前置,返回引用friend Point operator--(Point & ,int);//用友元函数实现后置,返回对象 // 前置或后置,一般应返回对象或引用,否则只能单独使用 // 既a++ 合法,而b=a++; 非法 }; Point & Point::operator++( )//前置,成员实现 { x++;y++; return *this; } Point Point::operator++(int)//后置,成员实现 { Point t=*this; x++;y++; return t; } Point & operator--(Point &p)//前置,友元实现 { p.x--; p.y--; return p; } Point operator--(Point &p,int)//后置,友元实现 { Point temp=p; p.x--;p.y--; return temp; } void main( ) { Point m(1,2), c; c=m++; // 如果只写m++; m.show( ); 则无法测出是前置还是后置 c.show( ); m.show( ); c=++m; c.show( ); m.show( ); c=m--; c.show( ); m.show( ); c=--m; c.show( ); m.show( ); } 4. 答案: #include #include class string { char *str; int len; public: string(char *s=0)//构造函数,含缺省构造函数 { if(s) //此处必须判断s是否为空指针。 { len=strlen(s); //若s为空指针,则strlen(s)报运行错。 str=new char[len+1]; strcpy(str,s); } else len=0,str=0; //注意逗号 } string(string &st) //拷贝构造函数,必须要定义,想一想为什么? { if(st.str) { len=st.len; str=new char[len+1]; strcpy(str,st.str); } else len=0,str=0; } ~string( ) //析构函数 { if(str) delete [ ]str; } void set(char *s) //置值 { if(str) delete [ ]str; //必须先删除原空间 if(s) { len=strlen(s); str=new char[strlen(s)+1]; strcpy(str,s); } else str=0,len=0; } void show(void) //显示串 { if(str) cout< else cout<<"The string is empty!"< } int getlen(void) //获取长度 { return len; } //解1 void delchar(char ch) //删除字符(删除所有参数指定的字符) { int i, j; for(i=j=0; str[i]; i++) if( str[i]!=ch ) str[j++]=str[i]; str[j]='\0'; char *t=str;//使字符串长度与成员len的值保持一致 str=new char[strlen(t)+1]; strcpy(str,t); len=strlen(str); delete [ ] t; } /* 解2 void delchar(char ch) //删除字符(删除所有参数指定的字符) { int i=0; if(str) //while(i while(str[i])//删除若干字符后,len与str指向的空间长度不一致if(str[i]==ch)//可处理成一致,亦可忽略这种不一致 { strcpy(str+i, str+i+1); len--;//注意 } else i++; } */ /* 解3 void delchar(char ch) { int i=0,j=0; if(str) for(;i { if(str[i]==ch) { j=i; for(;j str[j]=str[j+1]; len--; i--; } } } */ string& operator=(string &s) // 赋值运算只能用成员实现 { if(str) delete [ ]str; len=s.len; if(s.str) { str=new char[len+1]; strcpy(str,s.str); } else str=0; return *this; } string & operator+=(string &s) //字符串拼接+= { string t=*this; //调用拷贝构造函数,初始化t(保存老串) if(str) delete [ ] str; //删除老串 len=len+s.len; if(len) { str = new char[len+1]; strcpy(str,t.str); strcat(str,s.str); } return *this; } friend string operator+(string &s1, string &s2); //字符串拼接+,类外实现 int operator==(string &s) //字符串比较 { if(strcmp(str,s.str)==0) return 1; else return 0; //或return(!strcmp(str, s.str)); } }; string operator+(string &s1, string &s2) //字符串拼接+,类外实现 { string t; t.len=s1.len+s2.len; if(t.len) { t.str=new char[t.len+1]; strcpy(t.str,s1.str); strcat(t.str,s2.str); } else t.str=0; return t; //因为返回对象(动态申请空间),所以要定义拷贝构造函数} void main( ) { char *a="C plus plus "; string s1(a), s2("language"), s3;//测试两种构造函数 s1.show( ); s2.show( ); s3.show( ); cout << "Befor assign:\n"; if(s1==s2) //测试比较运算符= = cout<<"s1 and s2 is same!"< if(!(s1==s2)) cout<<"s1 and s2 is different!"< s1=s2; //测试赋值运算符= cout << "After assign s1=s2:\n"; if(s1==s2) cout<<"s1 and s2 is same!"< if(!(s1==s2)) cout<<"s1 and s2 is different!"< s3=s1+s2; //测试加法及赋值运算符+=,= s3.show( ); s3+=s2; //测试运算符+= s3.show( ); s3.delchar('e'); //想一想,能否处理成s3-'e'//测试删除字符串函数s3.show( ); s3.delchar('a'); s3.show( ); s3.delchar('g'); s3.show( ); } 5. 答案: #include class Matrix { int *p, m, n; public: Matrix(int mm, int nn ) { m=mm, n=nn; p=new int[m*n]; } Matrix(Matrix &b) { m=b.m; n=b.n; p=new int[m*n]; for(int i=0; i p[i] = (b.p)[i]; } void input( ) { int i; for(i=0; i cin>>p[i]; } Matrix operator+(Matrix &b) // ??? { if(m!=b.m || n!=b.n) { cout<<"The two matrix are not same size!\n"; return *this; } for(int i=0; i p[i] += (b.p)[i]; return *this; } void operator =( Matrix &b) { if(m!=b.m || n!=b.n) { cout<<"The two matrix are not same size!\n"; } for(int i=0; i p[i] = (b.p)[i]; } void show( ) { int i,j; int *p1=p; for(i=0; i { for(j=0; j cout<<(*p1++)<<'\t'; cout< } cout< } ~Matrix( ) { if(p) delete [ ] p; } }; void main(void) { int m,n; cout<<"Please input m & n : "; cin>>m>>n; Matrix A(m,n), B(m,n); cout<<"Please input the first matrix : "; A.input(); B = A; B.show( ); Matrix C(A); C.show( ); C=A+B; C.show(); } 6. 答案: #include class Shape { public: virtual double Area()=0; virtual void Setdata(double,double=0)=0; }; class Triangle:public Shape { double w,h; public: Triangle(double w1=0,double h1=0) { w=w1; h=h1; } void Setdata(double w1,double h1=0) { w=w1; h=h1; } double Area() { return ((w*h)/2); } }; class Rectangle:public Shape { double w,h; public: Rectangle(double w1=0,double h1=0) { w=w1; h=h1; } void Setdata(double w1,double h1=0) { w=w1; h=h1; } double Area() { return w*h; } }; class Square:public Shape { double s; public: Square(double s1=0){ s=s1;} void Setdata(double s1,double h1=0){s=s1;} double Area( ) { return s*s; } }; class Circle:public Shape { double r; public: Circle(double r1=0){ r=r1;} void Setdata(double r1,double h1=0){ r=r1;} double Area( ) { return (3.14*r*r); } }; double CalcArea(Shape *ps) { return(ps->Area()); } void main() { Triangle tri(3,4); Rectangle rec(4,5); Square squ; Circle cir; double s=2, r=8; squ.Setdata(s); cir.Setdata(r); double area=CalcArea(&tri)+CalcArea(&rec)+CalcArea(&squ)+CalcArea(&cir); cout << "The sum of area = "< }