实验八 多态性

实验八  多态性
实验八  多态性

实验八多态性

1.填空

(1)关键字operator 引入了重载运算符函数定义。

(2)不能重载的C++运算符是类属关系运算符"."、成员指针运算符".*"、作用域分辨符"::" 、sizeof运算符和三目运算符"?:" 。

(3)通过重载运算符不能修改运算符的操作对象个数、优先级、和结合性。

2、选择题,先选择,然后解释选择的理由:

(1) 运算符重载时不需要保持的性质是:(A )

A)操作数类型

B)操作数个数

C)优先级

D)结合性

解释:通过重载运算符不能修改运算符的操作对象个数、优先级、和结合性。但其他的可以改变。

(2) 有如下类定义和变量定义:

#include

class X

{

int a;

void setX (int x)

{a=x;}

public:

void showX()

{cout<<"a="<

};

class Y: private X{/*类定义省略*/};

class Z: public X{/*类定义省略*/};

Y objY;

Z objZ;

下列语句中正确的是:( D )

A) objY.setX(3);

B) objY.showX();

C) objZ.setX(4);

D) objZ.showX();

解释:对于A,C,无论何种继承方式,派生类均不可直接访问基类的私有成员。对于B,由于Y继承X时是私有继承,派生类Y不可直接访问X中的成员。

(3) 有如下类定义:

#include

class A

{ int xx;

public:

A():xx(0)

{cout<<'A';}

A(int n):xx(n)

{cout<<'B';}

};

class B:public A

{ int yy;

public:

B():yy(0){cout<

B(int n):A(n+1),yy(n)

{cout<

B(int m,int n):A(m),yy(n)

{cout<

};

下列选项中,输出结果为A0的语句是:( D ) A)B y1(0,0);

B)B y2(1);

C)B y3(0);

D)B y4;

解释:输出结果分别为

B0

B1

B0

A0

(4)有如下程序:

class A

{ public:

A() { f();}

~A() { ...... }

virtual void f();

void g(){f()};

};

class B: public A

{ public:

~B() { ...... }

void f();

void g();

};

B b; A *p; p = &b;

没有调用到A::f的语句是:( A)

A) p->f();

B) p->A::f();

C) p = new A;

D) p = new B;

解释:分别调用,A)调用B::f;B)调用A::f();C)调用A::f();D)调用B::B(),A::A(),A::f

(5)己知表达式a++中的“++”是作为友元函数重载的运算符,则与a++等效的运算符函数调用形式为:( C)

A)a .orerator++(1);

B)operator++(a);

C)operator++(a, 0);

D)a.operator++(a, 0 );

解释:由于是作为友元函数重载,根据由友元函数重载的规则,可排除ABD。

(6)有如下程序:

#include

class Base{

public:

virtual void fn(int x){ cout<<"Base::fn()"<

};

class Sub : public Base{

public:

virtual void fn(double x){ cout<<"Sub::fn()"; }

};

void test(Base& b){

b.fn(2);

}

int main()

{

Base a; test(a);

Sub b; test(b);

}

执行的结果是:( A )

A) Base::fn() Base::fn()

B) Base::fn() Sub::fn()

C) Sub::fn() Base::fn()

D) Sub::fn() Sub::fn()

解释:由于派生类的fn函数参数类型为double型,与基类类型不同,导致派生类的虚函数不能覆盖基类的虚函数,从而调用时均调用的是基类的fn函数。

3.

#include

using namespace std;

class Point

{

public:

Point (int val) { x = val; }

Point Point::operator++() //前置++运算符重载{ x++; return *this; }

Point Point::operator ++(int) //后置++运算符重载{ Point old = *this;

++(*this);

return old;

}

int GetX() { return x; }

private:

int x;

};

int main()

{ Point a(10);

cout << (++a).GetX();

cout << a++.GetX(); }

4.

#include

class Second;

class First

{

private:

int t;

public:

First(int x) { t=x; }

void print(Second &b);

};

class Second

{

private: int s;

public:

Second(int y) { s=y; }

friend void First::print(Second & w);

};

void First::print(Second & w)

{cout<<"First: "<

int main()

{ First m(6);

Second n(8);

m.print(n) ;

return 0;

}

5.

#include

using namespace std;

class CShape

{ public:

virtual float area()=0;

};

float total(CShape *s[ ],int n) //n为图形的个数

{ float sum=0.0; //各图形面积和for(int i=0;i

sum+=s[i]->area();

return sum;

}

class CTriangle:public CShape

{

public:

CTriangle(float w=0,float h=0);

float area(){return W*H*0.5;};

private:

float W,H;

};

class CRectangle:public CShape

{

public:

CRectangle(float w=0,float h=0);

float area(){return W*H;};

private:

int W,H;

};

CTriangle::CTriangle(float w,float h)

{W=w;H=h;}

CRectangle::CRectangle(float w,float h)

{W=w;H=h;}

int main()

{

float fArea;

CTriangle s1(1,2);

CRectangle s2(3,4);

CShape *s[]={&s1,&s2};

fArea=total(s,2);

cout<

}

6、友元运算符函数和成员运算符函数有什么不同?哪些运算符只能用友元?哪些运算符只能用成员函数?哪些两者均可?

解:

不同点:运算符函数如果是类的成员函数,则它具有一个隐含的this指针,this所指对象就成为第一个操作数。即用成员运算符函数表示一个双目运算符,该成员运算符函数有一个参数,表示第二个操作数;用成员运算符函数表示一个单目运算符,该成员运算符函数有没有参数。运算符运算符函数如果是类的友元函数,则它没有this指针。即用友元运算符函数表示一个双目运算符,该函数有两个参数;用友元运算符函数表示一个单目运算符,该函数有一个参数。友元运算符函数总是比成员运算符函数多一个函数参数。

只能用友元函数:第一个操作数不是类的操作对象。

只能用成员函数:这些运算符是:=(赋值)、[](下标)、()(函数调用)、->(通过指针访问成员),以及所有的类型转换运算符。

两者均可:在多数情况下,将运算符重载为类的成员函数和类的友元函数都是可以的。

在多数情况下,将运算符重载为类的成员函数和类的友元函数都是可以的。但成员函数运算符与友元函数运算符也具有各自的一些特点:

(1) 一般情况下,单目运算符最好重载为类的成员函数;双目运算符则最好重载为类的友元函数。

(2) 以下一些双目运算符不能重载为类的友元函数:=、()、[]、->。

(3) 类型转换函数只能定义为一个类的成员函数而不能定义为类的友元函数。

(4) 若一个运算符的操作需要修改对象的状态,选择重载为成员函数较好。

(5) 若运算符所需的操作数(尤其是第一个操作数)希望有隐式类型转换,则只能选用友元函数。

(6) 当运算符函数是一个成员函数时,最左边的操作数(或者只有最左边的操作数)必须是运算符类的一个类对象(或者是对该类对象的引用)。如果左边的操作数必须是一个不同类的对象,或者是一个内部类型的对象,该运算符函数必须作为一个友元函数来实现。

(7) 当需要重载运算符具有可交换性时,选择重载为友元函数。

7、判断对错,说明理由:

(1)重载函数和运算符都是是用静态联编实现的。因为:C++在编译时常采用“名字压延“的方法来区分重载函数。名字压延是在编译器“看”到函数后改变函数名。亦即C++把重载函数的本名和参数结合起来创造函数的新名字,在程序中每一处说明原型、定义和调用这些函数的地方,C++均用压延名字来替代。例如:

有以下两个函数原型:

int myAns(float x,int j);

int myAns(int i,char c);

并用以下语句调用它们:

exam1=myAns(15,3,15);

exam2=myAns(45,’a’);

则在编译完成之前,C++也许会将函数名改变成如下形式:

int myAnsFLTINT(float x,int j);

int myAnsINTCHAR(int I,char c);

同时C++也会在函数调用的地方改变名字,如:

exam1=myansFLTINT(15,3,15);

exam2=myAnsINTCHAR(45,’a’);

解:对。

(2)程序段:

complex complex::operator +(complex c2) //重载函数实现

{

complex c;

c.real=c2.real+real;

c.imag=c2.imag+imag;

return complex(c.real,c.imag);

}

中的语句:

return complex(c.real,c.imag);

可以用语句return c;

替换。因为在函数返回的时候,可以返回临时对象,也可以直接用类的构造函数来生成一个无名临时对象并返回它,而不对该对象命名。

解:对。

(3)要实现动态联编,派生类中的虚函数的参数类型可以与虚函数的原型不同。

解:错。这会导致派生类的虚函数不能覆盖基类的虚函数,也就不能实现动态联编。

8、存在这样的抽象类吗?该类定义中并没有定义纯虚函数。

解:存在。原因有二,

1,纯虚函数只需声明,不必给出定义。2,抽象类派生出新的类后,如果派生类没有给出全部纯虚函数的实现,这时的派生类仍是抽象类。

9、找出下面程序运行结果错误的原因(未按++运算符的要求做),并改正。

#include

class coord{

int x,y;

public:

coord(int i=0,int j=0);

void print();

friend coord operator++(coord &op);//

};

coord::coord(int i,int j)

{x=i;y=j;}

void coord::print()

{cout<<" x:"<

coord operator ++(coord &op)//

{ ++op.x;

++op.y;

return op;

}

main()

{ coord ob(10,20);

ob.print();

++ob;//

ob.print();

operator++(ob);//

ob.print();

return 0;

}

错误原因:值传递不会改变原数的值。

10、附加题:

(1)写出下列程序的运行结果,并分析该程序中关于“+”的运算符重载可以用成员函数实现吗?为什么?

#include

class AB

{

int a,b;

public:

AB(int x=0,int y=0)

{a=x;b=y;}

friend AB operator+(AB ob,int x);//友元函数

friend AB operator+(int x,AB ob);//友元函数

void print();

};

AB operator+ (AB ob,int x)//定义友元运算符函数

{ AB temp;

temp.a=ob.a+x;

temp.b=ob.b+x;

return temp;

}

AB operator+(int x,AB ob) //定义友元运算符函数

{ AB temp;

temp.a=x+ob.a;

temp.b=x+ob.b;

return temp;

}

void AB::print()

{cout<<"a="<

};

class perimenter:public circle{

public:

void show()//

{cout<<"perimenter is "<<2*3.14*r<

};

void main()

{ circle *ptr;

area ob1;

perimenter ob2;

ob1.setr(10);

ob2.setr(10);

ptr=&ob1;

ptr->show();

ptr=&ob2;

ptr->show();

}

解:运行结果:

area is 314

perimenter is 62.8

Press any key to continue

virtual void show()=0的含义是声明show为纯虚函数(即抽象函数),为子类提供一个统一的接口。

(3)写出下列程序的运行结果,并说明其结果为什么不是:

In Base class,int x=2

In Base class,int x=3

In Sube class,double x=2.0

In Sube class,double x=3.5

=====================================

#include

using namespace std;

class Base{

public:

virtual void fn(int x){ cout<<"In Base class, int x = "<

};

class Sub : public Base{

public:

virtual void fn(double x){ cout<<"In Sub class, double x = "<

};

void test(Base& b){

b.fn(2);

b.fn(3.5);

}

int main()

{

Base a;

test(a);

Sub b;

test(b);

}

解:运行结果:

In Base class, int x = 2

In Base class, int x = 3

In Base class, int x = 2

In Base class, int x = 3

Press any key to continue

因为派生类的fn函数参数类型为double型,与基类类型不同,导致派生类的虚函数不能覆盖基类的虚函数,从而调用时均调用的是基类的fn函数

所以结果不是

In Base class,int x=2

In Base class,int x=3

In Sube class,double x=2.0

In Sube class,double x=3.5

改为以下

#include

using namespace std;

class Base{

public:

virtual void fn(double x){ cout<<"In Base class, int x = "<<(int)x<<"\n"; }

};

class Sub : public Base{

public:

virtual void fn(double x){ cout<<"In Sub class, double x = "<

};

void test(Base& b){

b.fn(2);

b.fn(3.5);

}

int main()

{

Base a;

test(a);

Sub b;

test(b);

}

In Base class, int x = 2

In Base class, int x = 3

In Sub class, double x = 2

In Sub class, double x = 3.5

Press any key to continue

相关主题
相关文档
最新文档