实验1 类和对象
1.1 实验目的
1.掌握类的定义和使用方法,掌握类对象的声明和使用方法。
2.掌握对象的初始化和赋值的方法。
3.了解成员函数的特性、友元。
4.静态成员的使用方法。
5.理解和掌握this指针的用法。
6.理解和掌握const类型数据的使用。
1.2 实验内容
1.先阅读下列程序,写出执行结果。然后输入程序,调试程序,比较结果的正确性。
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
// 直角坐标类
class Point
{
private:
// 数据成员:
int x, y; // 横坐标与纵坐标
public:
// 公有函数:
Point(int a, int b): x(a), y(b) { } // 构造函数
void Set(int a, int b); // 设置坐标值
int GetX() const{ return x; } // 返回横坐标
int GetY()const{ return y; } // 返回纵坐标
};
// 直角坐标类及相关函数的实现部分
void Point::Set(int a, int b) // 设置坐标值
{
x = a; // 横坐标
y = b; // 纵坐标
}
void Show(const Point &pt) // 显示坐标值
{ cout << pt.GetX() << " " << pt.GetY() << endl; }
int main(void) // 主函数main(void)
{
Point a[5] = {Point(0, 0), Point(1, 1), Point(2, 2), Point(3, 3), Point(4, 4)}; // 由对象组成的数组
Point *p = a; // p指向数组a
p->Set(5, 9); // 设置坐标值
a[3].Set(6, 8); // 设置坐标值
for (int i = 0; i < 5; i++)
{ // 依次显示各对象的坐标值
Show(*p++);
}
system("PAUSE"); // 调用库函数system( ),输出系统提示信息
return 0; // 返回值0,返回操作系统
}
2.先阅读下列程序,写出执行结果。然后输入程序,调试程序,比较结果的正确性。
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
// 日期类
class Date
{
private:
// 数据成员:
int month, day, year; // 年月日
public:
// 公有函数:
Date(int m = 1, int d = 1, int y = 2008); // 构造函数
// 友元
friend void Show(const Date &dt); // 显示日期
};
// 日期类及相关函数的实现部分
Date::Date(int m, int d, int y) // 由m(月),d(日)和y(年)构造对象
{
this->month = m; // 月
this->day = d; // 日
this->year = y; // 年
}
void Show(const Date &dt) // 显示日期
{
cout << dt.month << "/" << dt.day << "/" << dt.year << endl;
}
int main(void) // 主函数main(void)
{
Date d1(6, 8, 2008), d2(6, 18), d3(5), d4; // 定义日期对象
Show(d1); // 显示d1
Show(d2); // 显示d2
Show(d3); // 显示d3
Show(d4); // 显示d4
system("PAUSE"); // 调用库函数system( ),输出系统提示信息
return 0; // 返回值0,返回操作系统
}
3.程序填空。下面程序主要测试静态成员的使用方法,请完成程序。
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
// 测试静态成员类
class Test
{
private:
// 数据成员:
static int count; // 对象数
public:
// 公有函数:
Test(){ count++; } // 构造函数, 实现对对象进行计数
static void Show(){ cout << "共有" << count << "个对象!" << endl; } // 显示对象数
};
[1] count = 0; // 为静态数据成员赋初值
int main(void) // 主函数main(void)
{
Test obj1, obj2, obj3; // 定义对象
Test::Show(); // 显示对象数
system("PAUSE"); // 调用库函数system( ),输出系统提示信息
return 0; // 返回值0,返回操作系统
}
4.改正下面程序中的错误,使其能正常运行。
// 文件名: main.cpp //1
#include <iostream> // 预处理命令 //2
using namespace std; // 使用标准命名空间std //3
//4
// 测试构造函数与析构函数类 //5
class Test //6
{ //7
public: //8
// 公有函数: //9
void Test(){ cout << "构造函数" << endl; } //10
void ~Test(){ cout << "析造函数" << endl; } //11
}; //12
//13
int main(void) // 主函数main(void) //14
{ //15
Test obj; // 定义对象 //16
//17
system("PAUSE"); // 调用库函数system( ),输出系统提示信息 //18
return 0; // 返回值0,返回操作系统 //19
} //20
5.编写设计一个People(人)类。该类的数据成员有年龄(age)、身高(height)、体重(weight)和人数(num),其中人数为静态数据成员,成员函数有构造函数(People)、进食(Eatting)、运动(Sporting)、睡眠(Sleeping)、显示(Show)和显示人数(ShowNum)。其中构造函数由已知参数年龄(a)、身高(h)和体重(w)构造对象,进食函数使体重加1,运动函数使身高加1,睡眠函数使年龄、身高、体重各加1,显示函数用于显示人的年龄、身高、体重,显示人数函数为静态成员函数,用于显示人的个数。假设年龄的单位为岁,身高的单位为厘米,体重的单位为市斤,要求所有数据成员为protected访问权限,所有成员函数为public访问权限,在主函数中通过对象直接访问类的所有成员函数。
*6.定义一个描述学生(Student)基本情况的类,数据成员包括姓名(name)、学号(num)、数学成绩(mathScore)、英语成绩(englishScore)、人数(count)、数学总成绩(mathTotalScore)和英语总成绩(englishTotalScore)。其中姓名定义为长度为18的字符数组,其它数据成员类型为整型,数学总成绩、英语总成绩和人数为静态数据成员,函数成员包括构造函数、显示基本数据函数(ShowBase)和显示静态数据函数(ShowStatic),其中构造函数由已知参数姓名(nm)、学号(nu)、数学成绩(math)和英语成绩(english)构造对象,显示基本数据函数用于显示学生的姓名、学号、数学成绩、英语成绩,显示静态数据函数为静态成员函数,用于显示人数,数学总成绩,英语总成绩;要求所有数据成员为private访问权限,所有成员函数为public访问权限,在主函数中定义若干个学生对象,分别显示学生基本信息,以及显示学生人数,数学总成绩与英语总成绩。
1.4 实验提示
1.通过构造函数生成对象为对象数组赋初值,属于基本输出cout方面的题目,应注意换行,语句
Point *p = a; // 指向p指向数组a
p->Set(5, 9); // 设置坐标值
用于修改对象数组的a[0]的值,而语句
a[3].Set(6, 8); // 设置坐标值
用于修改对象数组的a[3]的值。
2.注意缺省参数值的使用;对于私有数据成员,可使用友元进行访问。
3.中静态数据成员赋初值的一般形式如下:
数据类型类名::静态数据成员名=初值;
参考答案为:
[1]int Test::
4.构造函数与析构函数不能有返回值类型,因此应去掉第10行和第11行的void。
5.只要按题目要求编程实现即可,建议将比较短的函数在类体中实现,比较长的函数在类体外实现。
6.可仿照第5题编程实现,当然学生现实后还可灵活处理,比如定义学生数组存储学生信息,由count的值作为学号(此时构造函数的参数中不需要学号的信息)。
1.5 实验步骤
以实验内容第5题为例说明实验步骤。具体实现步骤如下:
1.建立工程exp2_5。
2.建立源程序文件main.cpp,具体内容如下:
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
// 人(people)类
class People
{
protected:
// 数据成员:
int age; // 年龄
int height; // 身高
int weight; // 体重
static int num; // 人数
public:
// 公有函数:
People(int a, int h, int w); // 构造函数
void Eatting(){ weight++; } // 进食使体重加1
void Sporting(){ height++; } // 运动使身高加1
void Sleeping(); // 睡眠
void Show() const; // 显示人的信息
static void ShowNum() // 显示人数
{ cout << "人数:" << num << endl; }
};
int People::num = 0; // 初始化静态数据成员num
// 人(people)类的实现部分
People::People(int a, int h, int w): age(a), height(h), weight(w)
{ num++; } // 由已知信息构造对象, 人数num将自加1
void People::Sleeping() // 睡眠
{
age++; // 睡眠使年龄加1
height++; // 睡眠使身高加1
weight++; // 睡眠使体重加1
}
void People::Show() const
// 显示人的信息
{
cout << "第" << num << "个人:" << endl; // 显示人的序号
cout << "年龄:" << age << "岁" << endl; // 显示年龄
cout << "身高:" << height << "厘米" <<endl; // 显示身高
cout << "体重:" << weight << "市斤" << endl;// 显示体重
cout << endl; // 换行
}
int main(void) // 主函数main(void)
{
People obj1(8, 120, 60); // 定义对象
obj1.Eatting(); // 进食
obj1.Sporting(); // 运动
obj1.Sleeping(); // 睡眠
obj1.Show(); // 显示信息
People obj2(18, 170, 108); // 定义对象
obj2.Eatting(); // 进食
obj2.Sporting(); // 运动
obj2.Sleeping(); // 睡眠
obj2.Show(); // 显示信息
People::ShowNum(); // 显示人数
system("PAUSE"); // 调用库函数system( ),输出系统提示信息
return 0; // 返回值0,返回操作系统
}
3.编译及运行程序。
1.6 测试与结论
以实验内容第5题为例进行测试,测试时,屏幕显示如下:
第1个人:
年龄:9岁
身高:122厘米
体重:62市斤
第2个人:
年龄:19岁
身高:172厘米
体重:110市斤
人数:2
请按任意键继续. . .
从上面的屏幕显示,可知本程序满足实验内容第5题的要求。
实验2 继承与派生
2.1 实验目的
1.熟练掌握类的继承,能够定义和使用类的继承关系。
2.掌握派生类的声明与实现方法。
3.掌握类构造函数的初始化列表与作用域分辨符的使用方法。
4.理解虚基类在解决二义性问题中的作用。
2.2 实验内容
1.先阅读下列程序,写出执行结果。然后输入程序,调试程序,比较结果的正确性。
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
class A
{
public:
// 公有函数:
A(){ cout << "构造A" << endl; } // 构造函数
~A(){ cout << "析构A" << endl; } // 析构函数
};
class B: public A
{
public:
// 公有函数:
B(){ cout << "构造B" << endl; } // 构造函数
~B(){ cout << "析构B" << endl; } // 析构函数
};
class C: public B
{
public:
// 公有函数:
C(){ cout << "构造C" << endl; } // 构造函数
~C(){ cout << "析构C" << endl; } // 析构函数
};
int main(void) // 主函数main(void)
{
C obj; // 定义对象
system("PAUSE"); // 调用库函数system( ),输出系统提示信息
return 0; // 返回值0, 返回操作系统
}
2.先阅读下列程序,写出执行结果。然后输入程序,调试程序,比较结果的正确性。
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
class A
{
protected:
// 数据成员:
int a; // 数据成员
public:
// 公有函数:
A(int x): a(x){ } // 构造函数
void Show() const{ cout << a << endl; } // 显示a之值
};
class B
{
protected:
// 数据成员:
int b; // 数据成员
public:
// 公有函数:
B(int x): b(x){ } // 构造函数
void Show() const{ cout << b << endl; } // 显示a与b之值
};
class C: public A, public B
{
public:
// 公有函数:
C(int x, int y): A(x), B(y){ } // 构造函数
void Show() const // 显示b之值
{ cout << a << "," << b << endl; }
};
int main(void) // 主函数main(void)
{
C obj(5, 18); // 定义对象
obj.Show(); // 显示相关信息
obj.A::Show(); // 显示相关信息
obj.B::Show(); // 显示相关信息
system("PAUSE"); // 调用库函数system( ),输出系统提示信息
return 0; // 返回值0, 返回操作系统
}
3.程序填空。下面程序主要测试类构造函数的初始化列表与作用域分辨符,请完成程序。
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
class A
{
private:
// 数据成员:
int a; // 数据成员
public:
// 公有函数:
A(int x): [1] { } // 构造函数
void Show() const // 显示a之值
{ cout << "a:" << a << endl; }
};
class B: public A
{
protected:
// 数据成员:
int b; // 数据成员
public:
// 公有函数:
B(int x, int y): [2] , b(y){ } // 构造函数
void Show() const // 显示相关信息
{
[3] Show(); // 调用基类A的成员函数Show()
cout << "b:" << b << endl; // 显示b之值
}
};
int main(void) // 主函数main(void)
{
B obj(5, 18); // 定义对象
obj.Show(); // 显示相关信息
system("PAUSE"); // 调用库函数system( ),输出系统提示信息
return 0; // 返回值0, 返回操作系统
}
4.改正下面程序中的错误,使其能正常运行。
// 文件名: main.cpp //1
#include <iostream> // 预处理命令 //2
using namespace std; // 使用标准命名空间std //3
//4
// 基类Base //5
class Base //6
{ //7
private: //8
// 数据成员: //9
int m; // 数据成员 //10
//11
public: //12
// 公有函数: //13
Base(int a): m(a){ } // 构造函数 //14
Base(const Base ©) : m(copy){ } // 复制构造函数 //15
void Show() const // 显示m之值 //16
{ cout << "m:" << m << endl; } //17
}; //18
//19
// 派生灰Derived //20
class Derived: private Base //21
{ //22
protected: //23
// 数据成员: //24
int n; // 数据成员 //25
//26
public: //27
// 公有函数: //28
Derived(int a, int b): b(a) { n =b; } // 构造函数 //29
void Show() const // 显示相关信息 //30
{ //31`
Base::Show(); // 调用基类Base的成员函数Show() //32
cout << "n:" << n << endl; // 显示n之值 //33
} //34
}; //35
//36
int main(void) // 主函数main(void) //37
{ //38
Derived obj(10, 18); // 定义对象 //39
obj.Show(); // 显示相关信息 //40
//41
system("PAUSE"); // 调用库函数system( ),输出系统提示信息 //42
return 0; // 返回值0, 返回操作系统 //43
} //44
5.定义Person(人)类,由Person分别派生出Teacher(教师)类和Cadre(干部)类,再由Teacher(教师)类和Cadre(干部)类采用多重继承方式派生出新类TeacherCadre(教师兼干部)类,各类之间的继承关系如图2.1所示。
图2.1 各类之间的继承关系
要求:
(1)在Person类中包含的数据成员有姓名(name)、年龄(age)、性别(sex)。在Teacher类还包含数据成员职称(title),在Cadre类中还包含数据成员职务(post),在TeacherCadre类中还包含数据成员工资(wages)。
(2)在类体中定义成员函数。
(3)每个类都有构造函数与显示信息函数(Show)。
*6.定义Staff(员工)类,由Staff分别派生出Saleman(销售员)类和Manager(经理)类,再由Saleman(销售员)类和Manager(经理)类采用多重继承方式派生出新类SaleManager(销售经理)类,各类之间的继承关系如图2.2所示。
图2.2 各类之间的继承关系
要求:
(1)在Staff类中包含的数据成员有编号(num)、姓名(name)、出勤率(rateOfAttend)、基本工资(basicSal)和奖金(prize)。在Saleman类中还包含数据成员销售员提成比例(deductRate)和个人销售额(personAmount),在Manager类中还包含数据成员经理提成比例(totalDeductRate)和总销售额(totalAmount)。在SaleManager类中不包含其它数据成员。
(2)各类人员的实发工资公式如下:
员工实发工资 = 基本工资 + 奖金 * 出勤率
销售员实发工资 = 基本工资 + 奖金 * 出勤率 + 个人销售额 * 销售员提成比例
经理实发工资 = 基本工资 + 奖金 * 出勤率 + 总销售额 * 经理提成比例
销售经理实发工资 =基本工资 + 奖金 * 出勤率 + 个人销售额 * 销售员提成比例+ 总销售额 * 经理提成比例
(3)每个类都有构造函数、输出基本信息函数(Output)和输出实发工资函数(OutputWage)。
2.4 实验提示
1.在创建派生类的对象时,系统先执行基类的构造函数,再执行派生类的构造函数;当派生类对象消亡时,系统会自动调用派生类的析构函数做一些必要的清理工作,析构函数调用的顺序是先派生类的析构函数,然后是基类的析构函数。
2.在类构造函数的初始化列表中,不但可以有基类,例如
C(int x, int y): A(x), B(y){ }
还可包含数据成员,例如
A(int x): a(x){ }
如果基类与派生类有同名成员函数,可以通过作用域分辨符明确指定调用哪个类的成员函数,例如
obj.A::Show(); // 调用基类A的成员函数Show()
3.知识点与第2题相同,读者应掌握构造函数的初始化列表与作用域分辨符的使用方法。参考答案为:
[1] a(x) [2] A(x) [3] A::
4.复制构造函数指构造函数以当前正在声明的类的对象作为参数,第15行就为复制构造函数的示例,在第15行的初始化列表中m(copy),由于m为整型,copy为对象,不能由copy直接由copy构造m,应改为
Base(const Base ©) { m = copy.m; } // 复制构造函数 //15
或
Base(const Base ©): m(copy.m){ } // 复制构造函数 //15
第29行的初始化列表中m(a)的m为基类Base的私有数据成员,对派生类Derived是不可见的,此处只能用基类名Base,具体修如下:
Derived(int a, int b): Base(a){ m =b; } // 构造函数 //29
5.为避免多义性,凡是几个类之间的继承关系如图1.1所示的菱形相似的关系,最好将位于菱形最上面的类声明为虑基类。
6.可仿照第5题编程实现,学生现实后还可灵活处理,比如在Staff(员工)类中增加静态累加器count,用count值产生员工编号,增加输入经理基本信息函数(Input),在main函数中用一个简单菜单循环选择输入与输出各类人员的信息。
2.5 实验步骤
以实验内容第5题为例说明实验步骤。具体实现步骤如下:
1.建立工程exp3_5。
2.建立源程序文件main.cpp,具体内容如下:
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
// 人(Person)类
class Person
{
protected:
// 数据成员:
char name[18]; // 姓名
int age; // 年龄
char sex[3]; // 性别
public:
// 公有函数:
Person(char nm[], int ag, char sx[]) // 构造函数
// 由已知参数nm(姓名), ag(年龄)和sx(性别)构造对象
{
strcpy(name, nm); // 姓名
age = ag; // 年龄
strcpy(sex, sx); // 性别
}
void Show() const // 显示相关信息
{
cout << "姓名:" << name << endl; // 显示姓名
cout << "年龄:" << age << endl; // 显示年龄
cout << "性别:" << sex << endl; // 显示性别
}
};
// 教师类
class Teacher: virtual public Person
{
protected:
// 数据成员:
char title[18]; // 职称
public:
// 公有函数:
Teacher(char nm[], int ag, char sx[], char tl[]): Person(nm, ag, sx)// 构造函数
{ strcpy(title, tl); } // 复制职称
void Show() const // 显示相关信息
{
Person::Show(); // 调用基类Person的成员函数Show()
cout << "职称:" << title << endl; // 显示职称
cout << endl; // 换行
}
};
// 干部类
class Cadre: virtual public Person
{
protected:
// 数据成员:
char post[18]; // 职务
public:
// 公有函数:
Cadre(char nm[], int ag, char sx[], char pt[]): Person(nm, ag, sx)// 构造函数
{ strcpy(post, pt); } // 复制职务
void Show() const // 显示相关信息
{
Person::Show(); // 调用基类Person的成员函数Show()
cout << "职务:" << post << endl; // 显示职务
cout << endl; // 换行
}
};
// 教师兼干部类
class TeacherCadre: public Teacher, public Cadre
{
protected:
// 数据成员:
double wages; // 工资
public:
// 公有函数:
TeacherCadre(char nm[], int ag, char sx[], char tl[], char pt[], double wg)
: Person(nm, ag, sx), Teacher(nm, ag, sx, tl), Cadre(nm, ag, sx, pt)
{ wages = wg; } // 复制工资
void Show() const // 显示相关信息
{
Person::Show(); // 调用基类Person的成员函数Show()
cout << "职称:" << title << endl; // 显示职称
cout << "职务:" << post << endl; // 显示职务
cout << "工资:" << wages << "元" << endl; // 显示工资
cout << endl; // 换行
}
};
int main(void) // 主函数main(void)
{
Teacher objTeacher("文冠杰", 48, "男", "教授"); // 定义对象
Cadre objCadre("周杰", 56, "男", "院长"); // 定义对象
TeacherCadre objTeacherCadre("李靖", 50, "女", "教授", "院长", 6890); // 定义对象
objTeacher.Show(); // 显示相关信息
objCadre.Show(); // 显示相关信息
objTeacherCadre.Show(); // 显示相关信息
system("PAUSE"); // 调用库函数system( ),输出系统提示信息
return 0; // 返回值0, 返回操作系统
}
3.编译及运行程序。
2.6 测试与结论
以实验内容第5题为例进行测试,测试时,屏幕显示如下:
姓名:文冠杰
年龄:48
性别:男
职称:教授
姓名:周杰
年龄:56
性别:男
职务:院长
姓名:李靖
年龄:50
性别:女
职称:教授
职务:院长
工资:6890元
请按任意键继续. . .
从上面的屏幕显示,可知本程序满足实验内容第5题的要求。
实验3 函数重载与运算符重载
3.1 实验目的
1.学习函数和操作符重载的使用方法。
2.理解函数和运算符重载的作用和意义。
3.掌握类运算符和友元运算符重载的定义和使用。
4.掌握常用运算符的重载。
3.2 实验内容
1.先阅读下列程序,写出执行结果。然后输入程序,调试程序,比较结果的正确性。
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
// 数组类
class Array
{
private:
// 数据成员:
int *elem; // 数组元素存储空间
int size; // 数组元素个数
public:
// 公有函数:
Array(int a[], int sz): elem(a), size(sz){ } // 构造函数
int GetSize(){ return size; } // 返回数组元素个数
int &operator[](int pos){ return elem[pos - 1]; } // 重载下标运算符[]
};
int main(void) // 主函数main(void)
{
int a[] = {1, 2, 3, 4, 5}; // 定义数组a
Array obj(a, 5); // 定义数组对象
obj[1] = 8; // 为数组元素赋值
for (int i = 1; i <= obj.GetSize(); i++) // 依次输出数组各元素之值
cout << obj[i] << " "; // 输出第i个元素
cout << endl; // 换行
system("PAUSE"); // 调用库函数system( ),输出系统提示信息
return 0; // 返回值0, 返回操作系统
}
2.程序填空。下面程序主要实现描述复数的类Complex的加法运算符+重载,试完成程序。
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
// 复数类
class Complex
{
private:
// 数据成员:
double realPart; // 实部
double imagePart; // 虚部
public:
// 公有函数:
Complex(double real = 0, double image = 0): realPart(real), imagePart(image){ } // 构造函数
double GetRealPart() const{ return realPart; } // 返回实部
double GetImagePart() const{ return imagePart; } // 返回虚部
[1] operator+(const Complex &a) const // 重载加法运算符+
{
Complex b; // 定义复数对象
b.realPart = this->realPart + a.realPart; // 和的实部
b.imagePart = this->imagePart + a.imagePart; // 和的虚部
return [2] ; // 返回和
}
};
int main(void) // 主函数main(void)
{
Complex a(1, 2), b(2, 6), c; // 定义复数对象
c = a + b; // 复数加法运算
cout << "a=" << a.GetRealPart() << "+" << a.GetImagePart() << "i" << endl; // 显示a
cout << "b=" << b.GetRealPart() << "+" << b.GetImagePart() << "i" << endl; // 显示b
cout << "c=" << c.GetRealPart() << "+" << c.GetImagePart() << "i" << endl; // 显示c
system("PAUSE"); // 调用库函数system( ),输出系统提示信息
return 0; // 返回值0, 返回操作系统
}
3.改正下面程序中的错误,使其能正常运行。
// 文件名: main.cpp //1
#include <iostream> // 预处理命令 //2
using namespace std; // 使用标准命名空间std //3
//4
// 整型类 //5
class Integer //6
{ //7
private: //8
// 数据成员: //9
int val; // 整数值 //10
//11
public: //12
// 公有函数: //13
Integer(){ val = 0; } // 无参数的构造函数 //14
Integer(int v = 0){ val = v; } // 带参数的构造函数 //15
void Show(){ cout << val << endl; } // 显示整数值 //16
}; //17
//18
int main(void) // 主函数main(void) //19
{ //20
Integer a(2), b; // 定义整型对象 //21
a.Show(); // 显示a //22
b.Show(); // 显示b //23
//24
system("PAUSE"); // 调用库函数system( ),输出系统提示信息 //25
return 0; // 返回值0, 返回操作系统 //26
} //27
4.设计一个日期类Date,,要求:
(1)包含年(year)、月(month)和日(day)私有数据成员。
(2)包含构造函数,重载关于一日期加上天数的加法运算符+、重载关于一日期减去天数的减加运算符-、重载输出运算符<<与输入运算符>>等。
*5.设计一个时间类Time,要求:
(1)包含时(hour)、分(minute)和秒(second)私有数据成员。
(2)包含构造函数,重载关于一时间加上另一时间的加法运算符+、重载关于一时间减去另一时间的减加运算符-、重载输出运算符<<与输入运算符>>等。
3.4 实验提示
1.在重载下标运算符时,已将关于下标pos的操作重载成elem[pos - 1],因此obj[1],obj[2],…,依次对应于elem[0],elem[1],…。
2.复数相加的结果也应为复数,所以[1]应填Complex,程序中b表示和,应为返回值,所以[2]应填写b,参考答案为:
[1] Complex [2] b
3.在定义整型对象b时,没有提供初始值,可使用无参数的构造函数,也可使用带参数的构造函数的缺省参数值0来构造整型对象,这样便产生了二义性,可去掉无参数的构造函数(去掉第14行),或去掉带参数的构造函数中的缺省值(去掉第15行中的“= 0”)。
4.由于各C++编译器对于重载输入/出运算符为友元的兼容性都存在问题,最好重载输入/出运算符不声明为成员函数与友元函数,而声明一般函数,为编序更方便,可增加一些成员函数,比如:
void SetYear(int y);} // 设置年
int SetMonth(int m); // 设置月
int SetDay(int d); // 设置日
int GetYear() const; // 返回年
int GetMonth() const; // 返回月
int GetDay() const; // 返回日
static int IsLeapyear(int y); // 判断年份y是否为润年
static int GetDays(int y); // 年份y的天数
static int GetDays(const Date &d); // 日期d当前月份的天数
static int DateToNum(const Date &d); // 返回从公元1年1月1日起的天数
static Date NumToDate(int n); //由从公元1年1月1日起的天数返回日期
润年条件:年份能被4整除,并且年份不能被100整除,或者年份能被400整除 润年天数:366 平年天数:365 润年2月份天数:29 平年2月份天数:28
5.可仿照第4题编程实现,可将时间转换成秒数,将秒数转成时间进行辅助编程。
时间转换成秒数:
秒数 = 时 * 3600 + 分 * 60 + 秒
秒数转换成时间:
时 = 秒数 / 3600 分 = (秒数 - 时 * 3600) / 60 秒 = 秒数 % 60
为编序更方便,可增加一些成员函数,比如:
void SetHour(int hh); // 设置小时
void SetMinute(int mm); // 设置分钟
void SetSecond(int ss); // 设置秒
int GetHour() const; // 返回小时
int GetMinute() const; // 返回分钟
int GetSecond() const; // 返回秒
3.5 实验步骤
以实验内容第4题为例说明实验步骤。具体实现步骤如下:
1.建立工程exp4_4。
2.建立源程序文件main.cpp,具体内容如下:
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
// 日期类
class Date
{
private:
// 数据成员:
int year; // 年
int month; // 月
int day; // 日
public:
// 公有函数:
Date(int y = 1, int m = 1, int d = 1): year(y), month(m), day(d){ } // 构造函数
void SetYear(int y){ year = y; } // 设置年
void SetMonth(int m){ month = m; } // 设置月
void SetDay(int d){ day = d; } // 设置日
int GetYear() const{ return year; } // 返回年
int GetMonth() const{ return month; } // 返回月
int GetDay() const{ return day; } // 返回日
Date operator+(int days); // 返回当前日期加上天数后得到的日期
Date operator-(int days); // 返回当前日期减去天数后得到的日期
static bool IsLeapyear(int y); // 判断年份y是否为润年
static int GetYearDays(int y); // 年份y的天数
static int GetMonthDays(const Date &d); // 日期d当前月份的天数
static int DateToNum(const Date &d); // 返回从公元1年1月1日起的天数
static Date NumToDate(int n); // 由从公元1年1月1日起的天数返回日期
};
ostream &operator<<(ostream &out, const Date &d); // 重载输出运算符
istream &operator>>(istream &in, Date &d); // 重载输入运算符>>
// 日期类及相关函数的实现部分
Date Date::operator+(int days) // 返回当前日期加上天数后得到的日期
{
int n = DateToNum(*this) + days; // 从公元1年1月1日起的天数
return NumToDate(n); // 返回日期
}
Date Date::operator-(int days) // 返回当前日期减去天数后得到的日期
{
int n = DateToNum(*this) - days; // 从公元1年1月1日起的天数
return NumToDate(n); // 返回日期
}
bool Date::IsLeapyear(int y) // 判断年份y是否为润年
{
if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0) return true; // 润年
else return false; // 平年
}
int Date::GetYearDays(int y) // 年份y的天数
{
if (IsLeapyear(y)) return 366; // 润年有366天
else return 365; // 平年有366天
}
int Date::GetMonthDays(const Date &d) // 日期d当前月份的天数
{
int n; // 天数
switch (d.GetMonth())
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
n = 31; // 第1,3,5,7,8,10,12月为大月
break;
case 4:
case 6:
case 9:
case 11:
n = 31; // 第4,6,9,11月为小月
break;
case 2:
if (IsLeapyear(d.GetYear())) n = 29;// 润年2月有29天
else n = 28; // 平年2月有29天
}
return n; // 返回当前月份的天数
}
int Date::DateToNum(const Date &d) // 返回从公元1年1月1日起的天数
{
int y, n = 0; // 年份与天数
for (y = 1; y < d.GetYear(); y++) // 累加从公元1年到year-1年的天数
n += GetYearDays(y);
for (int m = 1; m < d.GetMonth(); m++) // 累加从公元1月到month - 1月的天数
n += GetMonthDays(Date(y, m, 1));
n += d.GetDay(); // 累加当前月过的天数
return n; // 返回天数
}
Date Date::NumToDate(int n) // 由从公元1年1月1日起的天数返回日期
{
int y, m, d, rest = n; // 年,月,日和剩余天数
for (y = 1, rest = n; rest > GetYearDays(y); y++) // 计算年份
rest -= GetYearDays(y);
for (m = 1; rest > GetMonthDays(Date(y, m, 1)); m++) // 计算月份
rest -= GetMonthDays(Date(y, m, 1));
d = rest; // 日
return Date(y, m, d); // 返回日期
}
ostream &operator<<(ostream &out, const Date &d) // 重载输出运算符
{
out << d.GetYear() << "年" << d.GetMonth() << "月" << d.GetDay() << "日"; // 输出年月日
return out; // 返回输出流
}
istream &operator>>(istream &in, Date &d) // 重载输入运算符>>
{
int year, month, day; // 年月日
cin >> year >> month >> day; // 输入年月日
d = Date(year, month, day); // 转换成日期
return in; // 返回输入流
}
int main(void) // 主函数main(void)
{
Date d(2008, 8, 18); // 定义日期对象
cout << "日期:" << d << endl; // 输出日期
cout << "日期+10:" << d + 10 << endl; // 输出日期
cout << "日期-10:" << d - 10 << endl; // 输出日期
cout << "输入日期:";
cin >> d; // 输出日期
cout << "日期:" << d << endl; // 输出日期
system("PAUSE"); // 调用库函数system( ),输出系统提示信息
return 0; // 返回值0, 返回操作系统
}
3.编译及运行程序。
3.6 测试与结论
以实验内容第4题为例进行测试,测试时,屏幕显示如下:
日期:2008年8月18日
日期+10:2008年8月28日
日期-10:2008年8月8日
输入日期:2008 6 18
日期:2008年6月18日
请按任意键继续. . .
从上面的屏幕显示,可知本程序满足实验内容第4题的要求。
实验4 虚函数与多态性
4.1 实验目的
1.掌握虚函数的作用、定义和用途。
2.掌握纯虚函数的作用、定义和使用。
3.理解使用虚函数和继承实现多态性。
4.2 实验内容
1.先阅读下列程序,写出执行结果。然后输入程序,调试程序,比较结果的正确性。
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
// 基类
class Base
{
public:
// 公有函数:
virtual void f() { cout << "调用Base::f()" << endl; } // 虚函数
};
// 派生类
class Derived: public Base
{
public:
// 公有函数:
void f() { cout << "调用Derived::f()" << endl; } // 虚函数
};
int main(void) // 主函数main(void)
{
Derived obj; // 定义派生类对象
Base *p = &obj; // 基类指针
p->f(); // 调用函数f()
system("PAUSE"); // 调用库函数system( ),输出系统提示信息
return 0; // 返回值0, 返回操作系统
}
2.先阅读下列程序,写出执行结果。然后输入程序,调试程序,比较结果的正确性。
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
// 基类
class Base
{
public:
// 公有函数:
virtual void Show() const{ cout << "调用Base::Show()" << endl; } // 虚函数
};
// 派生类
class Derived: public Base
{
public:
// 公有函数:
void Show() const{ cout << "调用Derived::Show()" << endl; } // 虚函数
};
void Refers(const Base &obj) // 基类引用
{
obj.Show(); // 调用函数Show()
}
int main(void) // 主函数main(void)
{
Base obj1; // 定义对象
Derived obj2; // 定义对象
Refers(obj1); // 调用函数Refers()
Refers(obj2); // 调用函数Refers()
system("PAUSE"); // 调用库函数system( ),输出系统提示信息
return 0; // 返回值0, 返回操作系统
}
3.程序填空。请完成程序,使程序具有如下的输出:
168
158,158
158
程序如下:
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
// 基类
class Base
{
private:
// 数据成员:
int m; // 数据成员
public:
// 公有函数:
Base(int a): m(a){ } // 构造函数
virtual void Show() const { cout << m << endl; } // 虚函数
};
// 派生类
class Derived: public Base
{
private:
// 数据成员:
int n; // 数据成员
public:
// 公有函数:
Derived(int a, int b): Base(a), n(a){ } // 构造函数
void Show() const // 虚函数
{
cout << n << ","; // 显示n及","
Base::Show(); // 调用基类的Show()
}
};
int main(void) // 主函数main(void)
{
Base obj1(168); // 定义基类对象
Derived obj2(158, 98); // 定义派生类对象
Base *p; // 定义基类指针
p = &obj1; // 指向obj1
p->Show(); // 调用Show()
p = &obj2; // 指向obj2
p->Show(); // 调用Show()
p-> [1] ; // 调用基类的Show()
system("PAUSE"); // 调用库函数system( ),输出系统提示信息
return 0; // 返回值0, 返回操作系统
}
4.改正下面程序中的错误,使其能正常运行。
// 文件名: main.cpp //1
#include <iostream> // 预处理命令 //2
using namespace std; // 使用标准命名空间std //3
//4
// 基类 //5
class A //6
{ //7
public: //8
// 公有函数: //9
void ShowA() const{ cout << "基类A" << endl; } //10
}; //11
//12
// 派生类 //13
class B: public A //14
{ //15
public: //16
// 公有函数: //17
void ShowB() const{ cout << "派生类B" << endl; } //18
}; //19
//20
int main(void) // 主函数main(void) //21
{ //22
B obj; // 定义派生类对象 //23
A *p = &obj; // 定义基类指针指向派生类对象 //24
p->ShowB(); // 调用ShowB() //25
//26
system("PAUSE"); // 调用库函数system( ),输出系统提示信息 //27
return 0; // 返回值0, 返回操作系统 //28
} //29
5.编写程序,定义抽象基类Shape(形状),由它派生出2个派生类:Circle(圆形) 和Rectangle(矩形),用函数Show()分别显示各种图形的相关信息,最后还要显示所有图形的总面积。
*6.编写程序,定义抽象基类Shape(形状),由它派生出3个派生类: Circle(圆形)、Rectangle(矩形)和Square 正止方形),用函数函数ShowArea()分别显示各种图形的面积,最后还要显示所有图形的总面积。要求用基类指针数组,使它的每一个元素指向一一个派生类对象。
4.4 实验提示
1.基类指针指向派生类对象时,将调用派生类的虚函数。
2.通过基类的引用去引用基类对象,对象调用基类的虚函数;通过基类的引用去引用派生类对象,对象将调用派生类的虚函数。
3.由于输出结果是派生类调用基类的Show()函数完成的输出,这样要取消动态联编,使用作用域分辨符可达到目的参考答案为:
[1] Base::Show()
4.程序中声明了基类A和派生类B,在主函数main()中定义了基类A对象指针p,让p指向派生类B的对象,执行p->ShowB()调用成员函数。由于采用的是静态联编方式,通过指针p只能调用基类A的成员函数,而类A中没有ShowB()的成员函数,所以出错,可采用虚函数进行动态联编方法,具体修改如下:
virtual void Show() const{ cout << "基类A" << endl; } //10
void Show() const{ cout << "派生类B" << endl; } //18
p->Show(); // 调用Show() //25
5.在抽象基类Shape中定义静态数据成员sum用于累加各图形的面积,在各派生类的构造函数中分别累加各图形的面积。
*6.可仿照第5题编程实现;在主函数main()定义基类指针数组后,通过循环选择输入各种图形的相关信息并显示面积,注意最后要释放指针数组中指向的图形对象。
4.5 实验步骤
以实验内容第5题为例说明实验步骤。具体实现步骤如下:
1.建立工程exp5_5。
2.建立源程序文件main.cpp,具体内容如下:
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
const double PI = 3.1415926; // 常量PI
// 形状类
class Shape
{
public:
// 公有成员:
virtual void Show() const = 0; // 纯虚函数
static double sum; // 静态数据成员
};
// 圆形类
class Circle: public Shape
{
private:
// 数据成员:
double radius; // 半径
public:
// 公有函数:
Circle(double r): radius(r) // 构造函数
{ sum += PI * radius * radius; }
void Show() const // 显示圆形相关信息
{
cout << "圆形:" << endl;
cout << "半径:" << radius << endl; // 显示半径
cout << "面积:" << PI * radius * radius << endl; // 显示面积
}
};
// 矩形类
class Rectangle: public Shape
{
private:
// 数据成员:
double height; // 高
double width; // 宽
public:
// 公有函数:
Rectangle(double h, double w): height(h), width(w) // 构造函数
{ sum += height * width; }
void Show() const // 显示矩形相关信息
{
cout << "矩形:" << endl;
cout << "高:" << height << endl; // 显示高
cout << "宽:" << width << endl; // 显示宽
cout << "面积:" << height * width << endl; // 显示面积
}
};
double Shape::sum = 0; // 为静态数据成员赋初值
int main(void) // 主函数main(void)
{
char flag = 'Y'; // 判断是否继续录入的标志, 初始化为'Y'
Shape *p; // 基类指向
while (toupper(flag) == 'Y')
{
cout << "请选择输入类别(1.圆形 2.矩形)";
int select; // 临时变量
cin >> select; // 输入选择
switch (select)
{
case 1: // 圆形
double r; // 半径
cout << "输入半径:";
cin >> r; // 输入半径
p = new Circle(r); // 生成圆对象
p->Show(); // 显示相关信息
delete p; // 释放存储空间
break;
case 2: // 矩形
double h, w; // 高宽
cout << "输入高:";
cin >> h; // 输入高
cout << "输入宽:";
cin >> w; // 输入宽
p = new Rectangle(h, w); // 生成矩形对象
p->Show(); // 显示相关信息
delete p; // 释放存储空间
break;
default: // 其它情况, 表示选择有误
cout << "选择有误!"<< endl;
break;
}
cout << endl << "是否继续录入信息?(Y/N)";
cin >> flag;
}
cout << "总面积:" << Shape::sum << endl;
system("PAUSE"); // 调用库函数system( ),
return 0; // 返回值0, 返回操作系统
}
3.编译及运行程序。
4.6 测试与结论
以实验内容第5题为例进行测试,测试时,屏幕显示如下:
请选择录入类别(1.圆形 2.矩形)1
输入半径:2
圆形:
半径:2
面积:12.5664
是否继续录入信息?(Y/N)y
请选择录入类别(1.圆形 2.矩形)2
输入高:2
输入宽:6
矩形:
高:2
宽:6
面积:12
是否继续录入信息?(Y/N)n
总面积:24.5664
请按任意键继续. . .
从上面的屏幕显示,可知本程序满足实验内容第5题的要求。
实验5 模板
5.1 实验目的
1.了解模板的作用,熟悉函数模板和类模板的定义格式。
2.掌握函数模板与类模板的应用。
5.2 实验内容
1.先阅读下列程序,写出执行结果。然后输入程序,调试程序,比较结果的正确性。
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
template <class ElemType>
ElemType f(ElemType x)
{
ElemType y; // 临时变量
y = x * (ElemType)5.8;
return y;
}
int main(void) // 主函数main(void)
{
cout << f(5) << endl; // 输出f(5)
cout << f(5.0) << endl; // 输出f(5.0)
system("PAUSE"); // 调用库函数system( ), 输出系统提示信息
return 0; // 返回值0, 返回操作系统
}
2.先阅读下列程序,写出执行结果。然后输入程序,调试程序,比较结果的正确性。
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
void ShowMax(int a, int b) // 求两个整型数的最大值
{
int max = (a > b) ? a : b; // a与b的最大值
cout << "调用int, maxValue = " << max << endl;
}
void ShowMax(double a, double b ) // 求两个双精度型数的最大值
{
int max = (a > b) ? a : b; // a与b的最大值
cout << "调用double, maxValue = " << max << endl;
}
template <class ElemType1, class ElemType2>
void ShowMax(ElemType1 a, ElemType2 b)
{
ElemType1 max = (a > (ElemType1)b) ? a : (ElemType1)b;// a与b的最大值
cout << "调用函数模板, maxValue = " << max << endl;
}
int main(void) // 主函数main(void)
{
ShowMax(16, 518); // 显示最大值
ShowMax(16.0, 518.0); // 显示最大值
ShowMax(16.0, 518); // 显示最大值
system("PAUSE"); // 调用库函数system( ), 输出系统提示信息
return 0; // 返回值0, 返回操作系统
}
3.程序填空。请完成下面模板类的程序,使程序能正常运行。
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std // 使用标准命名空间std
class A
{
private:
// 数据成员:
int a; // 数据成员
public:
// 公有函数:
A(int x): a(x){ } // 构造函数
virtual void Show() const{ cout << a; } // 显示a之值
};
template <class ElemType>
class B: public A
{
private:
// 数据成员:
ElemType b; // 数据成员
public:
// 公有函数:
B(int x, ElemType y): A(x), b(y){ } // 构造函数
void Show() const
{
A::Show(); // 调用A的Show()
cout << " " << b << endl; // 显示b之值
}
};
int main(void) // 主函数main(void)
{
B< [1] > obj(8, "is my happy digit!"); // 定义对象
obj.Show(); // 显示相关信息
system("PAUSE"); // 调用库函数system( ),输出系统提示信息
return 0; // 返回值0, 返回操作系统
}
4.改正下面程序中的错误,使其能正常运行。
// 文件名: main.cpp //1
#include <iostream> // 预处理命令 //2
using namespace std; // 使用标准命名空间std //3
//4
template <class ElemType> //5
ElemType Max(ElemType a, ElemType b) // 返回最大值 //6
{ //7
return (a > b) ? a : b; // 返回a与b的最大值 //8
} //9
//11
int main(void) // 主函数main(void) //12
{ //13
cout << Max(16, 518) << endl; // 显示最大值 //14
cout << Max(16.8, 518) << endl; // 显示最大值 //15
//16
system("PAUSE"); // 调用库函数system( ), 输出系统提示信息 //17
return 0; // 返回值0, 返回操作系统 //18
} //19
5.编写一个使用数组类模板Array对数组进行排序、求最大值和求元素和的程序,并采用相关数据进行测试。
*6.对数组进行排序、求最大值和求元素和的函数采用静态成员函数的方式封装成数组算法类模板ArrayAlg,并采用相关数据进行测试。
*7.对数组进行排序、求最大值和求元素和的算法都编写为函数模板,采用相关数据进行测试。
5.4 实验提示
1.在调用f(5.0)时,由于5.0的类型为double,所以模板类型参数实例化为double,这样y = 5.0 * (double)5.8 = 29.0。
在调用f(5),由于5的类型为int,所以模板类型参数实例化为int,这样y = 5 * (int)5.8 = 25。
2.函数模板也可以重载。调用函数时,首先匹配类型完全相同的重载函数,其次,才寻求函数模板来匹配。
3.模板类B继承了基类A的性质,并可使用构造函数将参数传给基类。使用方法沿用类的规定,在模板B的构造函数中,第2个参数以模板类形式参数为类型,在main()函数中第2个参数为字符串,因此应将模板类形参数实例化为字符串类型char *,参考答案为:
[1] char *
4.这说明模板参数不具有隐式转换能力。在函数模板max的两个参数的类型都为相同模板类型参数,因此在实例化函数模板为模板函数时,两个参数类型应相同,在第15行模板函数max的两个实参的类型分别为双精度实形与整形,应将类型统一为双精度实型,具体修改如下:
cout << Max(16.8, 518.0) << endl; // 显示最大值 //15
或
cout << Max(16.8, (double)518) << endl; // 显示最大值 //15
5.对于对数组进行排序、求最大值和求元素和的函数可在类模板体内声明,在类模板体外实现。
*6.可仿照第5题对数组进行排序、求最大值和求元素和的实现;仿照实验6的第5题封装静态成员函数,具体静态成员函数可参考如下的声明:
static ElemType Max(ElemType elem[], int n); // 返回数组元素的最大值
static ElemType Sum(ElemType elem[], int n); // 返回数组元素之和
static void Sort(ElemType elem[], int n); // 排序
static void Show(ElemType elem[], int n); // 显示数组所有元素
练习代码:
#include<iostream>
using namespace std;
template<typename ElemType>//声明为模板类
class Array {
private:
// 数据成员:
ElemType* elem; // 数组元素存储空间
int n; // 数组元素个数
public:
// 公有函数:
Array(int a[], int sz) : elem(a), n(sz) { } // 构造函数
static ElemType Max(ElemType elem[], int n); // 返回数组元素的最大值
static ElemType Sum(ElemType elem[], int n); // 返回数组元素之和
static void Sort(ElemType elem[], int n); // 排序
static void Show(ElemType elem[], int n); // 显示数组所有元素
};
template<typename ElemType>
ElemType Array<ElemType>::Max(ElemType elem[], int n)
{
ElemType max = elem[0]; // 假设elem[0]最小
for (int i = 1; i < n; i++) // 依次比较求最新的最小值
{
if (max < elem[i]) {
max = elem[i];
}
}
return max; // 返回最大值
}
template<typename ElemType>
ElemType Array<ElemType>::Sum(ElemType elem[], int n)
{
ElemType sum = 0; // 用sum累加求和
for (int i = 0; i < n; i++)
{
sum += elem[i]; // 依次累加求和
}
return sum; // 返回最大值
}
template<typename ElemType>
void Array<ElemType>::Sort(ElemType elem[], int n)
{
for (int i = 0; i < n - 1; i++)
{ // 第i+1趟排序
int k = i; // 假设elem[i]最小
for (int j = i + 1; j < n; j++)
{
// 查找elem[i],elem[i+1],...,elem[size-1]中的最小值下标k
if (elem[k] > elem[j])
{
k = j;
}
}
if (k != i)
{ // 交换elem[j]和elem[k]
int tem; // 临时变量
tem = elem[i];
elem[i] = elem[k];
elem[k] = tem; // 循环赋值
}
}
}
template<typename ElemType>
void Array<ElemType>::Show(ElemType elem[], int n)
{
for (int i = 0; i < n; i++) { // 依次显示各元素的值
cout << elem[i] << " ";
}
cout << endl; // 换行
}
int main()
{
int a[] = { 6,3,1,4,5,3,5,26,8,15 }; // 定义数组a
Array<int>obj(a, 10);
cout << "原数组各元素的值:";
Array<int>::Show(a, 10); // 显示各元素的值
cout << "最大值为" << Array<int>::Max(a, 10) << endl;
cout << "元素之和为" << Array<int>::Sum(a, 10) << endl;
Array<int>::Sort(a, 10); // 排序
cout << "排序后数组各元素的值:";
Array<int>::Show(a, 10); // 显示各元素的值
return 0; // 返回值0, 返回操作系统
}
*7.可仿照第6题对数组进行排序、求最大值和求元素和的实现;直接编写为函数模板更简捷,但采用第6题的使用静态成员函数封装成类的方式在一般的集成开发环境(IDE)只要写出“类名::”(比如第6题只要写出ArrayAlg::)将实时显示类的成员列表,这样就不用再输入各函数的名称了,所以使用起更方便。具体函数模板可参考如下的声明:
template <class ElemType>
ElemType Max(ElemType elem[], int n); // 返回数组元素的最大值
template <class ElemType>
ElemType Sum(ElemType elem[], int n); // 返回数组元素之和
template <class ElemType>
void Sort(ElemType elem[], int n); // 排序
template <class ElemType>
void Show(ElemType elem[], int n); // 显示数组所有元素
5.5 实验步骤
以实验内容第5题为例说明实验步骤。具体实现步骤如下:
1.建立工程exp7_5。
2.建立源程序文件main.cpp,具体内容如下:
// 文件名: main.cpp
#include <iostream> // 预处理命令
using namespace std; // 使用标准命名空间std
// 数组类模板
template <class ElemType>
class Array
{
private:
// 数据成员:
ElemType *elem; // 数组元素存储空间
int size; // 数组元素个数
public:
// 公有函数:
Array(int a[], int sz): elem(a), size(sz){ } // 构造函数
ElemType Max(); // 返回数组元素的最大值
ElemType Sum(); // 返回数组元素之和
void Sort(); // 排序
void Show(); // 显示数组所有元素
};
// 数组类模板的实现部分
template <class ElemType>
ElemType Array<ElemType>::Max() // 返回数组元素的最大值
{
ElemType max = elem[0]; // 假设elem[0]最小
for (int i = 1; i < size; i++) // 依次比较求最新的最小值
{ if (max < elem[i]) max = elem[i]; }
return max; // 返回最大值
}
template <class ElemType>
ElemType Array<ElemType>::Sum() // 返回数组元素这和
{
ElemType sum = 0; // 用sum累加求和
for (int i = 0; i < size; i++){ sum += elem[i]; }// 依次累加求和
return sum; // 返回最大值
}
template <class ElemType>
void Array<ElemType>::Sort() // 排序
{
for (int i = 0; i < size - 1; i++)
{ // 第i+1趟排序
int k = i; // 假设elem[i]最小
for (int j = i + 1; j < size; j++) // 查找elem[i],elem[i+1],...,elem[size-1]中的最小值下标k
if (elem[k] > elem[j]) k = j;
if (k != i)
{ // 交换elem[j]和elem[k]
int tem; // 临时变量
tem = elem[i]; elem[i] = elem[k]; elem[k] = tem; // 循环赋值
}
}
}
template <class ElemType>
void Array<ElemType>::Show() // 显示数组所有元素
{
for (int i = 0; i < size; i++) // 依次显示各元素的值
cout << elem[i] << " ";
cout << endl; // 换行
}
int main(void) // 主函数main(void)
{
int a[] = {6, 2, 1, 4, 5, 3}; // 定义数组a
Array<int> obj(a, 6); // 定义数组对象
cout << "原数组各元素的值:";
obj.Show(); // 显示各元素的值
cout << "最大值为" << obj.Max() << endl;
cout << "元素之和为" << obj.Sum() << endl;
obj.Sort(); // 排序
cout << "排序后数组各元素的值:";
obj.Show(); // 显示各元素的值
system("PAUSE"); // 调用库函数system( ),输出系统提示信息
return 0; // 返回值0, 返回操作系统
}
3.编译及运行程序。
5.6 测试与结论
以实验内容第5题为例进行测试,测试时,屏幕显示如下:
原数组各元素的值:6 2 1 4 5 3
最大值为6
元素之和为21
排序后数组各元素的值:1 2 3 4 5 6
请按任意键继续. . .
从上面的屏幕显示,可知本程序满足实验内容第5题的要求。