实验1
1.掌握类的定义和使用方法,掌握类对象的声明和使用方法。
2.掌握对象的初始化和赋值的方法。
3.了解成员函数的特性、友元。
4.静态成员的使用方法。
5.理解和掌握this指针的用法。
6.理解和掌握const类型数据的使用。
1、实验内容
定义一个描述学生(Student)基本情况的类,数据成员包括姓名(name)、学号(num)、数学成绩(mathScore)、英语成绩(englishScore)、人数(count)、数学总成绩(mathTotalScore)和英语总成绩(englishTotalScore)。其中姓名定义为长度为18的字符数组,其它数据成员类型为整型,数学总成绩、英语总成绩和人数为静态数据成员,函数成员包括构造函数、显示基本数据函数(ShowBase)和显示静态数据函数(ShowStatic),其中构造函数由已知参数姓名(nm)、学号(nu)、数学成绩(math)和英语成绩(english)构造对象,显示基本数据函数用于显示学生的姓名、学号、数学成绩、英语成绩,显示静态数据函数为静态成员函数,用于显示人数,数学总成绩,英语总成绩;要求所有数据成员为private访问权限,所有成员函数为public访问权限,在主函数中定义若干个学生对象,分别显示学生基本信息,以及显示学生人数,数学总成绩与英语总成绩。
2、类的设计及说明
class Student {
private:
char name[18];//定义长度为18的姓名字符数组
int num;//学号
int mathScore, englishScore;//数学成绩,英语成绩
static int count, mathTotalScore, englishTotalScore;//人数,数学总成绩,英语总成绩
public:
Student(const char* nm, int nu, int math, int english);
//显示基本数据:
void showBase();
//显示静态数据:
static void ShowStatic();
};
分析:用对象数组存储3个对象:张三,李四,王五,并初始化基本数据:学号,数学成绩,英语成绩;在Student类的构造函数中定义:
count++;//计数器
mathTotalScore += math;//统计数学总成绩
englishTotalScore += english;//统计英语总成绩
所以3个对象会自动调用构造函数,使用for循环输出三个对象,然后在输出静态数据可以得到总人数为3,数学总成绩为89+79+69=237,英语总成绩为76+86+96=258。
心得体会:
1.该程序题主要测试类和对象的基本概念和使用规则;
2.学会使用类的构造函数:类内声明和初始化或者类内声明,类外初始化,掌握初始化列表;
3.学会区分静态成员和非静态成员,静态数据成员初始化的格式:数据类型 类名::静态数据成员名=初始值; 引用静态数据成员: 类名::静态数据成员名;
4.难点:对象数组的声明,访问,初始化;
5.可能会遇到的问题:使用strcpy()函数没有添加#include。
源代码如下:
#include<iostream>
#include<cstring>
using namespace std;
class Student {
private:
char name[18];//定义长度为18的姓名字符数组
int num;//学号
int mathScore, englishScore;//数学成绩,英语成绩
static int count, mathTotalScore, englishTotalScore;//人数,数学总成绩,英语总成绩
public:
Student(const char* nm, int nu, int math, int english);
//显示基本数据:
void showBase();
//显示静态数据:
static void ShowStatic();
};
Student::Student(const char* nm, int nu, int math, int english) :num(nu), mathScore(math), englishScore(english) {
strcpy(name, nm);
count++;//计数器
mathTotalScore += math;//统计数学总成绩
englishTotalScore += english;//统计英语总成绩
}
void Student::showBase() {
cout << "显示基本数据:\n" << endl;
cout << "姓名:" << name << endl;
cout << "学号:" << num << endl;
cout << "数学成绩:" << mathScore << endl;
cout << "英语成绩:" << englishScore << endl << endl;
}
void Student::ShowStatic() {
cout << "显示静态数据:\n" << endl;
cout << "总人数:" << count << endl;
cout << "数学总成绩:" << mathTotalScore << endl;
cout << "英语总成绩:" << englishTotalScore << endl;
}
//静态成员数据初始化
int Student::count = 0;
int Student::mathTotalScore = 0;
int Student::englishTotalScore = 0;
int main() {
//对象数组
Student stu[3] = { Student("张三",2018,89,76),
Student("李四",2019,79,86),
Student("王五",2020,69,96)
};
//遍历输出数组,打印基本数据
for (int i = 0; i < 3; i++) {
stu[i].showBase();
}
//打印静态数据
Student::ShowStatic();
return 0;
}
实验2
1.熟练掌握类的继承,能够定义和使用类的继承关系。
2.掌握派生类的声明与实现方法。
3.掌握类构造函数的初始化列表与作用域分辨符的使用方法。
4.理解虚基类在解决二义性问题中的作用。
1、实验内容
定义Staff(员工)类,由Staff分别派生出Saleman(销售员)类和Manager(经理)类,再由Saleman(销售员)类和Manager(经理)类采用多重继承方式派生出新类SaleManager(销售经理)类,各类之间的继承关系如图2.1所示。
图2.1 各类之间的继承关系
要求:
(1)在Staff类中包含的数据成员有编号(num)、姓名(name)、出勤率(rateOfAttend)、基本工资(basicSal)和奖金(prize)。在Saleman类中还包含数据成员销售员提成比例(deductRate)和个人销售额(personAmount),在Manager类中还包含数据成员经理提成比例(totalDeductRate)和总销售额(totalAmount)。在SaleManager类中不包含其它数据成员。
(2)各类人员的实发工资公式如下:
员工实发工资 = 基本工资 + 奖金 * 出勤率
销售员实发工资 = 基本工资 + 奖金 * 出勤率 + 个人销售额 * 销售员提成比例
经理实发工资 = 基本工资 + 奖金 * 出勤率 + 总销售额 * 经理提成比例
销售经理实发工资 =基本工资 + 奖金 * 出勤率 + 个人销售额 * 销售员提成比例+ 总销售额 * 经理提成比例
(3)每个类都有构造函数、输出基本信息函数(Output)和输出实发工资函数(OutputWage)。
2、类的设计及说明
//员工类
class Staff {
public:
Staff(int a, char* b, double c, double d, double e); //员工类构造函数声明
void Output1();//输出员工类基本信息
double OutputWage1(); //返回员工薪水
private:
int num;//编号
char name[18];//姓名
double rateOfattend;//出勤率
double basicSal;//基本工资
double prize;//奖金
};
//销售员类
class Saleman :virtual public Staff {
public:
Saleman(int a, char* b, double c, double d, double e, double f, double g);
void Output2();//输出 Staff+Saleman 基本信息
void output2(); // 只输出 Saleman 基本信息
double OutputWage2();
private:
double daductRatr; //成员销售额提成比例
double personAmount;//个人销售额
};
//经理类
class Manager :virtual public Staff {
public:
Manager(int a, char* b, double c, double d, double e, double f, double g);
void Output3();//输出 Staff+Manager 基本信息
void output3();//只输出 Manager 基本信息
double OutputWage3();//返回经理实发工资
private:
double totalDeductRate;
double totalAmount;
};
//销售经理类
class SaleManager :public Saleman, public Manager {
public:
SaleManager(int a, char* b, double c, int d, int e, double f, double g, double h, double i);
void Output4();//输出销售经理基本信息
double OutputWage4();//返回销售经理实发工资
};
分析:根据四个类的继承关系图,销售员类和经理类虚继承员工类,销售经历公有继承销售员类和销售经理类。然后传入相应的参数,计算每个类的实发工资。
员工实发工资:1000+5000.5=1250;
销售员实发工资:2000+30000.6+80000.1=4600;
经理实发工资:3000+40000.7+90000.05=6250;
销售经理实发工资:1000+5000.5+80000.1+90000.05=2500;
心得体会:
1、首先要理解继承类之间的关系:销售员类和经理类虚继承员工类,销售经历公有继承销售员类和销售经理类;
2、然后要理解多重继承构造函数的执行顺序;
3、为什么要引入虚基类,虚基类是如何有效避免产生二义性的;
4、在程序执行过程中出现实发工资计算不正确的问题,与实参和形参的对应关系有关;
实发工资函数 return 实发工资 要通过cout输出到屏幕,不放在输出基本信息函数中。
源代码
#include<iostream>
#include<cstring>
using namespace std;
//员工类
class Staff {
public:
Staff(int a, char* b, double c, double d, double e); //员工类构造函数声明
void Output1();//输出员工类基本信息
double OutputWage1(); //返回员工薪水
private:
int num;//编号
char name[18];//姓名
double rateOfattend;//出勤率
double basicSal;//基本工资
double prize;//奖金
};
//员工类构造函数初始化
Staff::Staff(int a, char* b, double c, double d, double e)
{
num = a;
strcpy(name, b);
rateOfattend = c;
basicSal = d;
prize = e;
}
// 输出员工类基本信息
void Staff::Output1() {
cout << "学号:" << num << endl;
cout << "姓名:" << name << endl;
cout << "出勤率:" << rateOfattend << endl;
cout << "基本工资:" << basicSal << endl;
cout << "奖金:" << prize << endl;
}
//返回员工实发工资
double Staff::OutputWage1()
{
double salary;
//员工实发工资 = 基本工资 + 奖金 * 出勤率
salary = basicSal + prize * rateOfattend;
return salary;
}
//销售员类
class Saleman :virtual public Staff {
public:
Saleman(int a, char* b, double c, double d, double e, double f, double g);
void Output2();//输出 Staff+Saleman 基本信息
void output2(); // 只输出 Saleman 基本信息
double OutputWage2();
private:
double daductRatr; //成员销售额提成比例
double personAmount;//个人销售额
};
Saleman::Saleman(int a, char* b, double c, double d, double e, double f, double g) :Staff(a, b, c, d, e)
{
daductRatr = f;
personAmount = g;
}
//输出 Staff+Saleman 基本信息
void Saleman::Output2() {
Output1();
cout << "销售员提成比例: " << daductRatr << endl;
cout << "个人销售额: " << personAmount << endl;
}
// 只输出 Saleman 基本信息
void Saleman::output2() {
cout << "销售员提成比例: " << daductRatr << endl;
cout << "个人销售额: " << personAmount << endl;
}
//返回销售员实发工资
double Saleman::OutputWage2() {
double salary;
//销售员实发工资 = 基本工资 + 奖金 * 出勤率 + 个人销售额 * 销售员提成比例
salary = Staff::OutputWage1() + personAmount * daductRatr;
return salary;
}
//经理类
class Manager :virtual public Staff {
public:
Manager(int a, char* b, double c, double d, double e, double f, double g);
void Output3();//输出 Staff+Manager 基本信息
void output3();//只输出 Manager 基本信息
double OutputWage3();//返回经理实发工资
private:
double totalDeductRate;
double totalAmount;
};
Manager::Manager(int a, char* b, double c, double d, double e, double f, double g) :Staff(a, b, c, d, e)
{
totalDeductRate = f; //经理提成比例
totalAmount = g;//总销售额
}
//输出 Staff+Manager 基本信息
void Manager::Output3() {
Output1();
cout << "经理提成比例:" << totalDeductRate << endl;
cout << "经理销售额:" << totalAmount << endl;
}
//只输出 Manager 基本信息
void Manager::output3() {
cout << "经理提成比例:" << totalDeductRate << endl;
cout << "经理销售额:" << totalAmount << endl;
}
//返回经理实发工资
double Manager::OutputWage3() {
double salary;
//经理实发工资 = 基本工资 + 奖金 * 出勤率 + 总销售额 * 经理提成比例
salary = Staff::OutputWage1() + totalAmount * totalDeductRate;
return salary;
}
//销售经理类
class SaleManager :public Saleman, public Manager {
public:
SaleManager(int a, char* b, double c, int d, int e, double f, double g, double h, double i);
void Output4();//输出销售经理基本信息
double OutputWage4();//返回销售经理实发工资
};
SaleManager::SaleManager(int a, char* b, double c, int d, int e, double f, double g, double h, double i) :
Saleman(a, b, c, d, e, f, g), Manager(a, b, c, d, e, h, i), Staff(a, b, c, d, e) {
}
void SaleManager::Output4() {
Staff::Output1();
Saleman::output2();
Manager::output3();
}
//返回销售经理实发工资
double SaleManager::OutputWage4() {
double salary;
//销售经理实发工资 = 基本工资 + 奖金 * 出勤率 + 个人销售额 * 销售员提成比例 + 总销售额 * 经理提成比例
salary = Saleman::OutputWage2() + Manager::OutputWage3() - Staff::OutputWage1();
return salary;
}
int main() {
//员工 s1
Staff s1(1, "s1", 0.5, 1000, 500);
s1.Output1();
cout<<"员工实发工资:"<<s1.OutputWage1()<<endl;
cout << "----------------------------------" << endl;
//销售员s2
Saleman s2(2, "s2", 0.6, 2000, 3000, 0.1, 8000);
s2.Output2();
cout<<"销售员实发工资:"<<s2.OutputWage2()<<endl;
cout << "----------------------------------" << endl;
//经理s3
Manager s3(3, "s3", 0.7, 3000, 4000, 0.05, 9000);
s3.Output3();
cout<<"经理实发工资:"<<s3.OutputWage3()<<endl;;
cout << "----------------------------------" << endl;
//销售经理s4
SaleManager s4(4, "s4", 0.5, 1000, 500, 0.1, 8000, 0.05, 9000);
s4.Output4();
cout<<"销售经理实发工资:"<<s4.OutputWage4()<<endl;
return 0;
}
实验3
1.学习函数和操作符重载的使用方法。
2.理解函数和运算符重载的作用和意义。
3.掌握类运算符和友元运算符重载的定义和使用。
4.掌握常用运算符的重载。
1、实验内容
设计一个时间类Time,要求:
(1)包含时(hour)、分(minute)和秒(second)私有数据成员。
(2)包含构造函数,重载关于一时间加上另一时间的加法运算符+、重载关于一时间减去另一时间的减加运算符-、重载输出运算符<<与输入运算符>>等。
心得体会:
1、运算符重载是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型;
2、可以通过成员函数实现运算符重载,比如代码中的加法运算符重载;
3、通过全局函数实现运算符重载,要访问类中的私有成员,需要在类中声明为友元函数;
4、C++中运行时的多态性主要是通过虚函数来实现的,而编译时的多态性是由函数重载和运算符重载来实现的。
5、重载流插入运算符">>"时,返回类型istream &是为了返回一个istream类的对象,以便进行连续输入。该程序题还需要使用判断语句判断输入时间的合理性。(一天24小时,1小时=60分,一分=60秒。)
源代码
#include<iostream>
using namespace std;
class Time {
//设置友元函数
friend Time operator-(const Time& T1, const Time& T2);
friend ostream& operator<<(ostream& out, Time& T);
friend istream& operator>>(istream& cin, Time& T);
public:
Time() {};
Time(int h, int m, int s) {
hour = h;
minute = m;
second = s;
//判断时间的规范性
if(hour>=24)
hour=hour%24;
if(minute>=60)
hour=hour+1;
minute=minute%60;
if(second>60)
minute=minute+1;
second=second%60;
}
//成员函数实现加法运算符重载
Time operator+(Time& t) {
Time T;
//判断时间规范性
if((this->hour + t.hour)>=24){
T.hour = (this->hour + t.hour)%24;
}else{
T.hour = this->hour + t.hour;
}
if((this->minute + t.minute)>=60){
T.hour+=1;
T.minute = (this->minute + t.minute)%60;
}else{
T.minute = this->minute + t.minute;
}
if((this->second + t.second)>=60){
T.minute+=1;
T.second = (this->second + t.second);
}else{
T.second = this->second + t.second;
}
return T;
}
private:
int hour;//时
int minute;//分
int second;//秒
};
//全局函数实现减法运算符重载
Time operator-(const Time& T1, const Time& T2) {
Time T(0, 0, 0);
//判断时间规范性
if((T1.hour - T2.hour)>=24){
T.hour = (T1.hour - T2.hour)%24;
}else{
T.hour = T1.hour - T2.hour;
}
if((T1.minute - T2.minute)>=60){
T.hour+=1;
T.minute = (T1.minute - T2.minute)%60;
}else{
T.minute = T1.minute - T2.minute;
}
if((T1.second - T2.second)>=60){
T.minute+=1;
T.second = (T1.second - T2.second);
}else{
T.second = T1.second - T2.second;
}
return T;
}
//重载输出运算符<<
ostream& operator<<(ostream& cout, Time& T)
{
cout << T.hour << "时" << T.minute << "分" << T.second << "秒" << endl;
return cout;
}
//重载输入运算符>>
istream& operator>>(istream& cin, Time& T) {
Time t;
char op;
//cout << "输入时针:" << endl;
cin >> T.hour>>op>>T.minute>>op>>T.second;//输入参数
if (T.hour >= 0 && T.hour < 24&&T.minute >= 0 && T.minute < 60&&T.second >= 0 && T.second < 60) {
t.hour = T.hour;
t.minute = T.minute;
t.second = T.second;
}
else{
cout << "输入有误,请重新输入" << endl;
cin >> T.hour>>op>>T.minute>>op>>T.second;//输入参数
}
return cin;
return cin;
}
int main() {
Time t0(12, 28, 68); // 检查时针进位
Time t1(28, 18, 12); // 检查分针进位
Time t2(13, 75, 24); // 检查秒针进位
Time t3, t4, t5, t6;
t3 = t1 + t2;
t4 = t2 - t1;
cout<<"----------------------------"<<endl;
cout << "t0: " << t0 << endl;
cout << "t1: " << t1 << endl;
cout << "t2: " << t2 << endl;
cout<<"----------------------------"<<endl;
cout << "t3 = t1 + t2: " << t3 << endl;
cout << "t4 = t2 - t1: " << t4 << endl;
cout << "(提示:出现负号表示t2 - t1<0;包括时分秒三种情况)"<<endl;
cout<<"------------------------------------------------------"<<endl;
cout << "请依次输入t5,t6并以回车键结束(hour:minute:second)" << endl;
cin >> t5>>t6;
cout << "\nt5: " << t5 << endl;
cout << "t6: " << t6 << endl;
}