实验四:类的继承、派生和多态
实验目的
1. 理解类的继承和派生机制
2. 掌握派生类的定义和使用
3. 理解和掌握派生类成员的标识和访问中同名覆盖原则、二元作用域分辨符和虚基类的用法
4. 掌握派生类构造函数和析构函数的定义及调用次序
5. 理解运算符重载的目的,掌握运算符重载函数的编写方法
实验内容
1. 车辆基本信息管理 问题场景描述如下: 为了对车量基本信息进行管理,对现实世界车量基本信息抽象后,抽象出Car类、ElectricCar类、Battery类, 它们之间的关系描述如下:基于Car类派生出ElectricCar类,派生类ElectricCar中新增数据成员为Battery类 对象。
基于以下描述设计并实现Battery类
· 每个Battery类对象有如下信息:
车载动力电池容量(batterySize)
· 要求Battery类提供成员函数实现以下要求:
带有默认形参值的构造函数。
实现Battery类对象的构造,在构造对象时对电池容量batterySize 进行初始化,默认参数值为70(单位: kWh)。
返回当前电池容量。
基于以下描述设计并实现Car类
· 每辆汽车有如下信息:
制造商(maker), 型号(model), 生产年份(year), 行车里程数(odometer)。
· 要求Car类提供成员函数实现以下要求:
带参数的构造函数。实现Car类对象的构造,并在构造对象时实现对制造商、型号、生产年份的 初始化。初始构造时,行车里程数总是0。
重载运算符<<为Car类友元。实现车辆信息显示输出,输出信息包括:制造商、型号、生产年 份、当前行车里程数。
更新行车里程数。更新后的行车里程数通过参数传递。要求能对参数进行合理性检查,如果更 新后的行车里程数值小于当前行车里程数,打印警告信息,提示更新数值有误。
基于以下描述设计并实现ElectricCar类
· ElectricCar类继承自Car类,新增数据成员电池(battery)。其中,battery是Battery类对象。
· 带参数的构造函数。
· 实现ElectricCar类对象的构造,并在构造时实现对制造商、型号、生产年份以及 新增数据成员电池的初始化。初始构造时,行车里程数总是0。
· 重载运算符<<为ElectricCar类友元。实现车辆信息显示输出,包括:制造商、型号、生产年份、当前 行车里程数、当前电池容量。
#ifndef Battery_h #define Battery_h #include<iostream> using namespace std; class Battery{ public: Battery(int battertSize0=70); int getbatterySize(); friend class ElectricCar; private: int batterySize; }; #endif
#ifndef CAR_H #define CAR_H #include<string> #include<iostream> using namespace std; class Car{ public: Car(string maker0, string model0, int year0, int odometer0=0); friend ostream & operator<<(ostream &out,const Car &c); void updateOdometer(double odometer); string getmaker() { return maker; } string getmodel() { return model; } int getyear() { return year; } double getodometer() { return odometer; } private: string maker; string model; int year; double odometer; }; #endif
#ifndef ElectricCar_H #define ElectricCar_H #include"car.h" #include"battery.h" #include<string> #include<iostream> using namespace std; class Battery; class ElectricCar:public Car { public: ElectricCar(string maker0,string model0,int year0,int odometer0=0); void batt(int battery); friend ostream & operator<<(ostream &out,ElectricCar &d); private: Battery battery; int b; }; #endif
#include"battery.h" #include<iostream> using namespace std; Battery::Battery(int batterySize0){ batterySize=batterySize0; }
#include"car.h" #include<iostream> using namespace std; ostream & operator<<(ostream &out,const Car &c){ out<<"maker:"<<c.maker<<endl<<"model:"<<c.model<<endl<<"year:"<<c.year<<endl<<"odometer:"<<c.odometer<<endl; return out;} Car::Car(string maker0, string model0,int year0,int odometer0){ maker=maker0; model=model0; year=year0; odometer=odometer0;} void Car::updateOdometer(double odometer0){ while(odometer>odometer0){ cout<<"Data error,please enter again:"; cin>>odometer0;} odometer=odometer0; }
#include"electricCar.h" #include<iostream> using namespace std; ostream & operator<<(ostream &out,ElectricCar &d){ out<<"maker:"<<d.getmaker()<<endl<<"model:"<<d.getmodel()<<endl<<"year:"<<d.getyear()<<endl<<"odometer:"<<d.getodometer()<<endl<<"batterySize:"<<d.b<<"-kWh"<<endl; return out;} ElectricCar::ElectricCar(string maker0, string model0, int year0, int odometer0) :Car(maker0, model0, year0, odometer0) { battery.batterySize = 70; b=battery.batterySize; }
#include <iostream> using namespace std; #include "car.h" #include "electricCar.h" int main() { // 测试Car类 Car oldcar("Audi","a4",2016); cout << "--------oldcar's info--------" << endl; oldcar.updateOdometer(25000); cout << oldcar << endl; // 测试ElectricCar类 ElectricCar newcar("Tesla","model s",2016); newcar.updateOdometer(2500); cout << "\n--------newcar's info--------\n"; cout << newcar << endl; system("pause"); return 0; }
运行结果
2.补足程序,重载运算符[]为一维动态整形数组类ArrayInt的成员函数,使得通过动态整形数组对象名和下标可以 访问对象中具体元素。
#ifndef ARRAY_INT_H #define ARRAY_INT_H class ArrayInt{ public: ArrayInt(int n, int value=0); ~ArrayInt(); // 补足:将运算符[]重载为成员函数的声明 // ××× int &operator[](int i); void print(); private: int *p; int size; }; #endif
#include "arrayInt.h" #include <iostream> #include <cstdlib> using std::cout; using std::endl; ArrayInt::ArrayInt(int n, int value): size(n) { p = new int[size]; if (p == nullptr) { cout << "fail to mallocate memory" << endl; exit(0); } for(int i=0; i<size; i++) p[i] = value; } ArrayInt::~ArrayInt() { delete[] p; } void ArrayInt::print() { for(int i=0; i<size; i++) cout << p[i] << " "; cout << endl; } // 补足:将运算符[]重载为成员函数的实现 // ××× int& ArrayInt::operator[](int i){ return p[i]; }
#include <iostream> using namespace std; #include "arrayInt.h" int main() { // 定义动态整型数组对象a,包含2个元素,初始值为0 ArrayInt a(2); a.print(); // 定义动态整型数组对象b,包含3个元素,初始值为6 ArrayInt b(3, 6); b.print(); // 通过对象名和下标方式访问并修改对象元素 b[0] = 2; cout << b[0] << endl; b.print(); system("pause"); return 0; }
运行结果
实验总结与体会
继承与派生较能理解,运算符重载只会照搬书上的框架和套路,比较生疏。
整体掌握较弱,第一个实验需要同学的帮助才能够解决问题。