一、实验目的和要求
了解静态联编的动态联编的概念。掌握动态联编的条件。
二、实验内容
1.分析并调试下列程序。
-
//sy6_1.cpp
-
#include<iostream>
-
using
namespace
std;
-
class
Base
-
{
-
public
:
-
virtual
void
f(
float
x){cout<<
“Base::f(float)”
<<x<<endl;}
-
void
g(
float
x){cout<<
“Base::g(float)”
<<x<<endl;}
-
void
h(
float
x){cout<<
“Base::h(float)”
<<x<<endl;}
-
};
-
class
Derived:
public
Base
-
{
-
public
:
-
virtual
void
f(
float
x){cout<<
“Derived::f(float}”
<<x<<endl;}
-
void
g(
int
x){cout<<
“Derived::g(int)”
<<x<<endl;}
-
void
h(
float
x){cout<<
“Derived::h(float)”
<<x<<endl;}
-
};
-
int
main()
-
{
-
Derived d;
-
Base *pb=&d;
-
Derived *pd=&d;
-
pb->f(3.14f);
-
pd->f(3.14f);
-
pb->g(3.14f);
-
pb->h(3.14f);
-
pd->h(3.14f);
-
return
0;
-
}
(1)找出以上程序中使用了重载和覆盖函数。
(2)写出程序的输出结果,并解释输出结果。
程序运行结果如下:
解释输出结果:
pb和pd指向同一地址,它们运行结果应该是相同的,但实际运行出来的结果却不相同,原因是决定pb和pd调用函数运行结果的不是他们指向的地址,而是他们的指针类型。“只有在通过基类指针或引用间接指向派生类子类型时多态性才会起作用”。在程序中pb是基类指针,pd是派生类指针,pd的所有函数调用都只是调用自己的函数,和多态性无关,所以pd的所有函数调用的结果都输出Derived::是完全正常的;pb的函数调用如果有virtual则根据多态性调用派生类的,如果没有virtual则是正常的静态函数调用,还是调用基类的,所以有virtual的f函数调用输出Derived::,其它两个没有virtual则还是输出Base::。
2. 分析并调试下列程序.
-
#include<iostream>
-
using
namespace
std;
-
class
Base
-
{
-
public
:
-
void
f(
int
x){cout<<
“Base::f(int)”
<<x<<endl;}
-
void
f(
float
x){cout<<
“Base::f(float)”
<<x<<endl;}
-
virtual
void
g(
void
){cout<<
“Base::g(void)”
<<endl;}
-
};
-
class
Derived:
public
Base
-
{
-
public
:
-
virtual
void
g(
void
){cout<<
“Derived::g(void}”
<<endl;}
-
};
-
int
main()
-
{
-
Derived d;
-
Base *pb=&d;
-
pb->f(42);
-
pb->f(3.14f);
-
pb->g();
-
return
0;
-
}
(1)找出以上程序中使用了重载和覆盖函数。
(2)写出程序的输出结果,并解释输出结果。
输出结果如下:
3. 分析并调试下列程序。
-
//sy6_3.cpp
-
#include<iostream>
-
using
namespace
std;
-
class
Point
-
{
-
public
:
-
Point(
double
i,
double
j){x=i;y=j;}
-
double
Area(){
return
0.0;}
-
private
:
-
double
x,y;
-
};
-
class
Rectangle:
public
Point
-
{
-
public
:
-
Rectangle(
double
i,
double
j,
double
k,
double
l):Point(i,j){w=k;h=l;}
-
double
Area(){
return
w*h;}
-
private
:
-
double
w,h;
-
};
-
int
main()
-
{
-
Point p(3.5,7);
-
double
A=p.Area();
-
cout<<
“Area= ”
<<A<<endl;
-
Rectangle r(1.2,3,5,7.8);
-
A=r.Area();
-
cout<<
“Area= ”
<<A<<endl;
-
return
0;
-
}
写出程序的输出结果,并解释输出结果。
输出结果如下:
4. 分析并调试下列程序。
-
//sy6_4.cpp
-
#include<iostream>
-
using
namespace
std;
-
const
double
PI=3.1415;
-
class
Shap
-
{
-
public
:
-
virtual
double
Area()=0;
-
};
-
class
Triangle:
public
Shap
-
{
-
public
:
-
Triangle(
double
h,
double
w){H=h;W=w;}
-
double
Area(){
return
0.5*H*W;}
-
private
:
-
double
H,W;
-
};
-
class
Rectangle:
public
Shap
-
{
-
-
public
:;
-
Rectangle(
double
h,
double
w){H=h;W=w;}
-
double
Area(){
return
H*W;}
-
private
:
-
double
H,W;
-
};
-
class
Circle:
public
Shap
-
{
-
public
:
-
Circle(
double
r){R=r;}
-
double
Area(){
return
PI*R*R;}
-
private
:
-
double
R;
-
};
-
class
Square:
public
Shap
-
{
-
public
:
-
Square(
double
s){S=s;}
-
double
Area(){
return
S*S;}
-
private
:
-
double
S;
-
};
-
double
Total(Shap *s[],
int
n)
-
{
-
double
sum=0;
-
for
(
int
i=0;i<n;i++)
-
sum+=s[i]->Area();
-
return
sum;
-
}
-
int
main()
-
{
-
Shap *s[5];
-
s[0]=
new
Square(8.0);
-
s[1]=
new
Rectangle(3.0,8.0);
-
s[2]=
new
Square(12.0);
-
s[3]=
new
Circle(8.0);
-
s[4]=
new
Triangle(5.0,4.0);
-
double
sum=Total(s,5);
-
cout<<
“SUM = ”
<<sum<<endl;
-
return
0;
-
}
运行结果如下:
(1)指出抽象类。
(2)指出纯虚函数,并说明它的作用。
(3)每个类的作用是什么?整个程序的作用是什么?
5. 某学校对教师每个月工资的计算规定如下:固定工资+课时补贴;教授的固定工资为5000元,每个课时补贴50;副教授的固定工资为3000,每个课时补贴30元;讲师的固定工资为2000元,每个课时补贴20元。定义教师抽象类,派生不同职称的教师类,编写程序求若干个教师的月工资。(sy6_5.cpp)
编写程序如下:
-
//sy6_5.cpp
-
#include <iostream>
-
using
namespace
std;
-
class
Teacher
-
{
-
public
:
-
virtual
int
Salary()=0;
-
virtual
void
Print(
int
)=0;
-
};
-
-
class
Professor:
public
Teacher
-
{
-
private
:
-
char
name[128];
-
int
lessons;
-
public
:
-
Professor()
-
{
-
cout<<
“请输入姓名:”
;
-
cin>>name;
//字符串中不能有空格
-
cout<<
“请输入课时:”
;
-
cin>>lessons;
//必须输入数字
-
};
-
int
Salary()
-
{
-
return
(5000+lessons*50);
-
};
-
void
Print(
int
money)
-
{
-
cout<<
“职称:教授 姓名:”
<<name<<
” 薪水:”
<<money<<endl<<endl;
-
};
-
};
-
-
class
AssociateProfessor:
public
Teacher
-
{
-
private
:
-
char
name[128];
-
int
lessons;
-
public
:
-
AssociateProfessor()
-
{
-
cout<<
“请输入姓名:”
;
-
cin>>name;
-
cout<<
“请输入课时:”
;
-
cin>>lessons;
-
};
-
int
Salary()
-
{
-
return
(3000+lessons*30);
-
};
-
void
Print(
int
money)
-
{
-
cout<<
“职称:副教授 姓名:”
<<name<<
” 薪水:”
<<money<<endl<<endl;
-
};
-
};
-
-
class
Lecturer:
public
Teacher
-
{
-
private
:
-
char
name[128];
-
int
lessons;
-
public
:
-
Lecturer()
-
{
-
cout<<
“请输入姓名:”
;
-
cin>>name;
-
cout<<
“请输入课时:”
;
-
cin>>lessons;
-
};
-
int
Salary()
-
{
-
return
(2000+lessons*20);
-
};
-
void
Print(
int
money)
-
{
-
cout<<
“职称:讲师 姓名:”
<<name<<
“薪水:”
<<money<<endl<<endl;
-
};
-
};
-
-
int
main()
-
{
-
Teacher *t = NULL;
-
-
int
money=0;
-
//教授
-
t =
new
Professor();
-
money = t->Salary();
-
t->Print(money);
-
delete
t;
-
-
//副教授
-
t =
new
AssociateProfessor();
-
money = t->Salary();
-
t->Print(money);
-
delete
t;
-
-
//讲师
-
t =
new
Lecturer();
-
money = t->Salary();
-
t->Print(money);
-
delete
t;
-
t = NULL;
-
return
0;
-
}
程序运行结果如下:
6. 把实验5中的第4题的Shape类定义为抽象类,提供共同操作界面的纯虚函数。TwoDimShape类和ThreeDimShape类仍然抽象类,第3层具体类才能提供全部函数的实现。在测试函数中,使用基类指针实现不同派生类对象的操作。
三、分析与讨论
1.结合实验内容中第1题和第2题,说明重载与覆盖的区别。 答:重载与覆盖的区别:1、方法的覆盖是子类和父类之间的关系,是垂直关系;方法的重载是同一个类中方法之间的关系,是水平关系2、覆盖只能由一个方法,或只能由一对方法产生关系;方法的重载是多个方法之间的关系。3、覆盖要求参数列表相同;重载要求参数列表不同。4、覆盖关系中,调用那个方法体,是根据对象的类型(对象对应存储空间类型)来决定;重载关系,是根据调用时的实参表与形参表来选择方法体的。